Compare commits

..
202 Commits
Author SHA1 Message Date
TrèsAbhi 5234c4d5c3 New translations en.json (Ukrainian)
[ci skip]
2026-08-12 11:53:33 -05:00
TrèsAbhi 0848833568 New translations en.json (Russian)
[ci skip]
2026-08-12 11:53:32 -05:00
TrèsAbhi d858a498cc New translations en.json (Portuguese)
[ci skip]
2026-08-12 11:53:31 -05:00
TrèsAbhi 7b81a59788 New translations en.json (Polish)
[ci skip]
2026-08-12 11:53:29 -05:00
TrèsAbhi e6d3bff381 New translations en.json (Japanese)
[ci skip]
2026-08-12 11:53:28 -05:00
TrèsAbhi 58e91f0af7 New translations en.json (Spanish)
[ci skip]
2026-08-12 11:53:26 -05:00
TrèsAbhi 137488bd0a New translations en.json (French)
[ci skip]
2026-08-12 11:53:25 -05:00
TrèsAbhi 92fd8b4457 New translations en.json (Chinese Simplified)
[ci skip]
2026-08-12 11:53:24 -05:00
TrèsAbhi 7829c206e9 New translations en.json (Ukrainian)
[ci skip]
2026-08-01 21:18:01 -05:00
TrèsAbhi 5872028678 New translations en.json (Ukrainian)
[ci skip]
2026-08-01 19:52:35 -05:00
TrèsAbhi a0cb819805 New translations en.json (Ukrainian)
[ci skip]
2026-07-31 20:53:17 -05:00
TrèsAbhi d714bfe57e New translations en.json (Russian)
[ci skip]
2026-07-31 20:53:16 -05:00
TrèsAbhi 1c35cd4128 New translations en.json (Portuguese)
[ci skip]
2026-07-31 20:53:14 -05:00
TrèsAbhi 0bdd1b1dca New translations en.json (Polish)
[ci skip]
2026-07-31 20:53:13 -05:00
TrèsAbhi b621790244 New translations en.json (Japanese)
[ci skip]
2026-07-31 20:53:12 -05:00
TrèsAbhi 0f08f4beee New translations en.json (Spanish)
[ci skip]
2026-07-31 20:53:11 -05:00
TrèsAbhi 799ea30bcb New translations en.json (French)
[ci skip]
2026-07-31 20:53:09 -05:00
TrèsAbhi dedb90d404 New translations en.json (Chinese Simplified)
[ci skip]
2026-07-31 20:53:08 -05:00
TrèsAbhi 6eafbc87e7 New translations en.json (Chinese Simplified)
[ci skip]
2026-07-31 14:08:23 -05:00
TrèsAbhi f84460d637 New translations en.json (Chinese Simplified)
[ci skip]
2026-07-31 12:32:17 -05:00
TrèsAbhi 917d6affea New translations en.json (Chinese Simplified)
[ci skip]
2026-07-13 06:04:31 -05:00
tresabhi cb2d795461 fix url 2026-07-11 18:14:22 -05:00
tresabhi 6e934e0ff1 logs 2026-07-11 18:13:02 -05:00
tresabhi 375adadbe5 Merge branch 'main' into dev 2026-07-11 18:04:36 -05:00
tresabhi 082a756f1b auto scroll on drag in tier list 2026-07-11 18:02:49 -05:00
tresabhi 9fc8a8e2a2 more generous pitch transition zones 2026-07-11 17:41:14 -05:00
tresabhi 1413475679 bigger floor and more aggressive light decay 2026-07-11 17:38:11 -05:00
tresabhi 86504e685e softer shadows 2026-07-11 17:33:37 -05:00
tresabhi 9df81044d1 increasing lighting angle to cover larger tanks 2026-07-11 17:29:44 -05:00
tresabhi c5fd7591ea complete lighting animation even if canvas is unfocused 2026-07-11 17:29:15 -05:00
TrèsAbhi cd8e43f945 Merge pull request #256 from Hitjack007/mixer-crashing 2026-07-11 17:17:11 -05:00
tresabhi 8df112aab4 type-safe disposal 2026-07-11 17:16:52 -05:00
TrèsAbhi 94c04ce102 Merge pull request #255 from Hitjack007/external-ricochets 2026-07-11 17:14:10 -05:00
TrèsAbhi 3a170202ca Merge pull request #254 from Hitjack007/he-crash-fix 2026-07-11 17:10:49 -05:00
tresabhi 46937693a0 implement nullable refs in a type-safe manner 2026-07-11 17:09:38 -05:00
TrèsAbhi b391d0b036 Merge pull request #253 from Hitjack007/static-armor-uncapitalised-fix 2026-07-11 17:06:29 -05:00
Mark Greene 1061e003f7 Fix Safari crash on mixer texture disposal 2026-07-10 21:30:21 +12:00
Mark Greene a2b573abca fix ricochets on external modules 2026-07-10 17:51:32 +12:00
Mark Greene 4571d141e6 Fix crash on repeated HE shell clicks in Tankopedia armor viewer 2026-07-10 16:03:05 +12:00
Mark Greene d70225b03c fix static armor plate title to use localized strings
Was rendering the raw lowercase layerTypeNames key instead of resolving it through strings.website.tools.tankopedia.sandbox.dynamic.shot_card.element, same pattern already used in ShotDisplayCard.
2026-07-10 15:41:46 +12:00
tresabhi dc6c528167 logs 2026-07-05 14:06:46 -05:00
tresabhi b4d5d4c16e reduce ground brightness in static mode 2026-07-05 14:04:09 -05:00
tresabhi f2f6d4ff49 add persistent count for the number of model users to unload only when
uses drops to 0
2026-07-05 13:44:04 -05:00
tresabhi cdbb7647f0 fixed fill and clip rule naming 2026-07-05 13:41:21 -05:00
TrèsAbhi 41e40de791 New Crowdin updates (#251)
* New translations en.json (Ukrainian)

[ci skip]

* New translations en.json (Ukrainian)

[ci skip]

* New translations en.json (Ukrainian)

[ci skip]
2026-07-04 22:05:48 -05:00
tresabhi c85cd36818 logs 2026-06-28 11:11:37 -05:00
tresabhi 5d2c63fed9 clean up some renderer stuff 2026-06-26 14:05:26 -05:00
tresabhi cead140855 optimize intro naimaiton 2026-06-26 14:01:39 -05:00
tresabhi 63a0143d4f optimize scene lighting and rnederer 2026-06-26 13:58:30 -05:00
tresabhi 19f22993f1 optimize shot display animator 2026-06-26 13:31:40 -05:00
tresabhi b2eb74914f optimize lighting loop 2026-06-26 13:22:24 -05:00
TrèsAbhi 05572918b1 exit 2026-06-23 10:35:27 -05:00
TrèsAbhi 1cc8b26b16 dispose 2026-06-23 10:30:56 -05:00
TrèsAbhi a8e8d20cf1 break 2026-06-23 10:26:05 -05:00
TrèsAbhi 55deb30607 logs 2026-06-23 10:20:22 -05:00
TrèsAbhi 03b8b89a17 log 2026-06-23 10:14:37 -05:00
TrèsAbhi 3e421c7eb7 done 2026-06-23 10:11:18 -05:00
TrèsAbhi fc27caabdc dvpl 2026-06-23 10:07:54 -05:00
tresabhi 3d35fae5ce dont log 2026-06-22 20:52:51 -05:00
tresabhi f6dfc4f176 what 2026-06-22 20:32:14 -05:00
tresabhi fdbbe2f356 Update applyPatches.ts 2026-06-22 20:18:25 -05:00
tresabhi cdf2aee43f debug 2026-06-22 20:13:52 -05:00
tresabhi 56933ddfac debug 2026-06-22 20:07:55 -05:00
tresabhi 1df2e818be dirs 2026-06-22 19:57:41 -05:00
tresabhi 1e4d00ea34 source 2026-06-22 19:55:39 -05:00
tresabhi 1bde50e0a3 garbage code 2026-06-22 19:54:09 -05:00
tresabhi 88290ec1ab garbage code 2026-06-22 19:54:01 -05:00
tresabhi e8325df832 lz4js 2026-06-22 19:44:03 -05:00
tresabhi 394f28e6ed remove proxyclient 2026-06-22 19:33:52 -05:00
tresabhi f5f170bcca switch to clean dava 2026-06-22 19:32:26 -05:00
tresabhi 2ffe3fc006 set up patches 2026-06-22 19:28:02 -05:00
TrèsAbhi 406d70b5b7 New translations en.json (Ukrainian) (#250)
[ci skip]
2026-06-22 09:38:55 -05:00
TrèsAbhi f801e81c8b New Crowdin updates (#249)
* New translations en.json (Russian)

[ci skip]

* New translations en.json (Russian)

[ci skip]
2026-06-17 09:26:26 -05:00
TrèsAbhi a0e1d8cee0 New Crowdin updates (#247)
* New translations en.json (Russian)

[ci skip]

* New translations en.json (Russian)

[ci skip]

* New translations en.json (Russian)

[ci skip]

* New translations en.json (Russian)

[ci skip]
2026-06-14 09:49:53 -05:00
TrèsAbhi a9a870c3e6 New translations en.json (Russian) (#245)
[ci skip]
2026-05-22 14:52:47 -05:00
TrèsAbhi 3d061a78de Merge pull request #242 from blitzkit/fixes
Fixes
2026-05-14 22:48:01 -05:00
TrèsAbhi a188a01244 Merge branch 'main' into fixes 2026-05-14 22:47:53 -05:00
TrèsAbhi 0828722876 logs 2026-05-15 03:47:40 +00:00
TrèsAbhi 0ccd9e45d8 Merge pull request #243 from karelpak1/fix-tank-icons-riff
fix: use RIFF sprite bounds for tank icon extraction
2026-05-14 22:36:09 -05:00
TrèsAbhi 2f745a16d1 clean up 2026-05-12 18:08:02 -05:00
TrèsAbhi 100c7391fb dispose models on unload 2026-05-12 17:54:50 -05:00
TrèsAbhi 4f42a31f53 Reduce interval timing from 60fps to 200ms 2026-05-11 17:52:23 -05:00
TrèsAbhi 0b2e322112 disbale low tiers 2026-05-11 17:14:22 -05:00
TrèsAbhi 042a1afa74 remove cache from useModel 2026-05-11 16:18:54 -05:00
TrèsAbhi 3edf4a25be impossible inspect element 2026-05-10 21:55:33 -05:00
TrèsAbhi 43237c2aee Merge pull request #244 from karelpak1/feat-tankopedia-modules-tooltips
feat: add localized tooltips to tankopedia modules tree
2026-05-02 10:03:15 -05:00
GonnaHetzMeandTrèsAbhi 2fffdc3ef5 Update packages/website/src/components/Tankopedia/CharacteristicsSection/components/Modules.tsx
Co-authored-by: TrèsAbhi <[email protected]>
2026-04-30 21:58:39 +02:00
GonnaHetzMe 76e748f0ed feat: add localized tooltips to tankopedia modules tree 2026-04-29 23:03:59 +02:00
GonnaHetzMe c353119962 fix: use RIFF sprite bounds for tank icon extraction 2026-04-29 21:19:43 +02:00
TrèsAbhi 5fa4d3b242 remove aeson 2026-04-28 16:17:40 -05:00
TrèsAbhi 068e0e26b0 Merge pull request #240 from karelpak1/fix-R5G6B5 2026-04-14 11:33:37 -05:00
TrèsAbhi f6ca77f8c8 Merge pull request #241 from karelpak1/chore-bump-version 2026-04-14 11:32:55 -05:00
TrèsAbhi 4c7eda81ca Merge pull request #239 from karelpak1/fix-alphatest-culling 2026-04-14 11:32:18 -05:00
TrèsAbhi 3948af9e39 fix: implement types and simplify code 2026-04-14 11:31:16 -05:00
GonnaHetzMe aec30e1944 chore: bump github actions versions 2026-04-13 02:13:53 +02:00
GonnaHetzMe 4205b16769 fix: correct RGB565 PVR decoding 2026-04-13 02:00:12 +02:00
GonnaHetzMe 4d13803b0c feat: culling 2026-04-12 22:35:55 +02:00
GonnaHetzMe b950ac1318 fix: sc2 alphatest threshold 2026-04-12 22:17:55 +02:00
TrèsAbhi 1920be28d8 Merge branch 'main' into fixes 2026-04-09 21:17:47 -05:00
TrèsAbhi 8b00772958 feat: logs 2026-04-09 21:17:34 -05:00
TrèsAbhi e2e38dc4b3 revert 2026-04-09 21:12:16 -05:00
TrèsAbhi 455f1be041 fix: use asset for diff 2026-04-08 09:05:10 -05:00
TrèsAbhi 3e37368038 Merge pull request #236 from karelpak1/fix-pitch-quickinput
fix: correct input pitch offset for initial turret rotation
2026-04-08 08:39:25 -05:00
TrèsAbhi 4b86e20a13 New Crowdin updates (#232)
* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Russian)
2026-04-08 08:38:28 -05:00
TrèsAbhi d9a14924eb Merge pull request #235 from karelpak1/fix-child-node-position
fix: position of child nodes
2026-04-08 08:38:07 -05:00
GonnaHetzMe 7d9d322405 fix: correct input pitch offset for initial turret rotation 2026-04-08 14:04:06 +02:00
GonnaHetzMe 5365044017 fix: position of child nodes 2026-04-08 08:48:53 +02:00
TrèsAbhi 069edf0847 feat: hot script 2026-04-07 17:00:35 -05:00
TrèsAbhi 2cdcf95822 fix: don't repeat reveal animation on scroll for tank sandbox 2026-04-07 16:57:04 -05:00
TrèsAbhi e43231aa97 fix: remove cue4parse 2026-04-07 16:44:03 -05:00
TrèsAbhi 0df2acd5e6 fix: equalizer in characteristics 2026-04-07 16:43:48 -05:00
TrèsAbhi 3f0b3f190a Merge pull request #234 from karelpak1/feat-riff-container 2026-04-07 16:31:47 -05:00
GonnaHetzMe 504f143ff7 fix: resolve requested changes 2026-04-07 23:15:26 +02:00
GonnaHetzMe 7cfc30c7a1 feat: add RIFF container support 2026-04-07 22:35:17 +02:00
TrèsAbhi f3ed687f00 Merge branch 'main' into fixes 2026-04-04 20:13:35 -05:00
TrèsAbhi e37575148c feat: logs 2026-04-04 20:13:25 -05:00
TrèsAbhi 2df9979f08 fix: armor highlghting in equalizer 2026-04-04 20:10:40 -05:00
TrèsAbhi c8ce26d6a7 Merge pull request #233 from karelpak1/fix-hp-equalizer 2026-04-04 19:52:21 -05:00
TrèsAbhi 898fd4bbf6 feat: simplify 2026-04-04 19:51:56 -05:00
GonnaHetzMe 744f7195dd fix: hp fix in Equalize 2026-04-05 02:14:09 +02:00
TrèsAbhi bc4f51846d Update tankCharacteristics.ts 2026-04-03 23:21:50 -05:00
TrèsAbhi ab8dc131b8 fix: don't build protos on setup 2026-04-03 22:18:39 -05:00
TrèsAbhi 684d33071e feat: logs 2026-04-03 22:15:44 -05:00
TrèsAbhi 146e68fc53 fix: penetration 2026-04-03 22:05:49 -05:00
TrèsAbhi 655b87d876 feat: compare equalize 2026-04-03 15:02:50 -05:00
TrèsAbhi 71caa2f703 fix: static 2026-04-03 14:53:14 -05:00
TrèsAbhi 99c95a4c15 fix: use code 2026-04-03 14:37:45 -05:00
TrèsAbhi 93632a7073 fix: a few missing chars 2026-04-03 14:29:23 -05:00
TrèsAbhi 297265822b feat: equal button 2026-04-03 13:04:55 -05:00
TrèsAbhi a7f799b5b6 fix: pen previwe 2026-04-03 12:59:22 -05:00
TrèsAbhi b176ec6c96 feat: penetration testing 2026-04-03 12:57:43 -05:00
TrèsAbhi 1a008a4852 feat: equalizer for visual armor sandbox 2026-04-03 12:31:46 -05:00
TrèsAbhi 145de2bbbc feat: shot card equalizer 2026-04-03 12:15:03 -05:00
TrèsAbhi 77c516a6eb feat: implement most equalizer 2026-04-03 12:08:47 -05:00
TrèsAbhi 6835004945 feat: equalizer parsing 2026-04-03 11:47:58 -05:00
TrèsAbhi e36823c159 feat: equalizer protos 2026-04-03 11:10:45 -05:00
TrèsAbhi ec6ac128f2 feat: beta badge for equializer 2026-04-03 11:05:12 -05:00
TrèsAbhi d80f47a6c8 fix: handle duplicate armor 2026-04-01 22:06:42 -05:00
TrèsAbhi 3a9af7505f fix: update to new api 2026-04-01 21:40:15 -05:00
TrèsAbhi 34ee954502 feat: local vfs 2026-04-01 21:34:44 -05:00
TrèsAbhi b9878a05a1 Merge branch 'main' into fixes 2026-04-01 21:18:12 -05:00
TrèsAbhi e9412bc404 revert: april fool's 2026-04-01 21:17:46 -05:00
TrèsAbhi 6755115c8a sick 2026-03-31 22:19:18 -05:00
TrèsAbhi e8ed4615fe what am i even doing bro 2026-03-31 22:18:03 -05:00
TrèsAbhi c55f4c311f fix: typo 2026-03-31 21:02:36 -05:00
TrèsAbhi e063970c58 feat: plug 2026-03-31 21:01:00 -05:00
TrèsAbhi fdf8580f5f feat: functionality 2026-03-31 17:15:25 -05:00
TrèsAbhi cffd37c6f1 feat: ui 2026-03-31 17:01:47 -05:00
TrèsAbhi 7419b3f29e fix: consumable times 2026-03-31 16:51:07 -05:00
TrèsAbhi e2f50871ec fix: update all 2026-03-31 14:11:45 -05:00
TrèsAbhi bdea9fdab3 fix: consistent protos 2026-03-31 13:35:47 -05:00
TrèsAbhi ae793c1c28 Merge pull request #229 from karelpak1/fix-large-repair-kit-icon 2026-03-26 20:05:56 -05:00
GonnaHetzMe 3d912036a7 fix: use proper icon for large repair kit 2026-03-27 02:03:15 +01:00
TrèsAbhi 1866077a82 Merge pull request #228 from karelpak1/feat-dev-name
Feat: dev name
2026-03-26 08:08:20 -05:00
TrèsAbhi 8345f99603 fix: use dev name directly 2026-03-26 08:06:43 -05:00
GonnaHetzMe 2ab576a37c fix: Set pointer cursor and simplify devName access 2026-03-26 09:29:35 +01:00
GonnaHetzMe 5b9ff7acb3 feat: CopyableCode styles and remove DEV name fallback 2026-03-25 17:25:52 +01:00
GonnaHetzMe 4cdb712013 feat: add CopyableCode component 2026-03-25 11:18:53 +01:00
GonnaHetzMe e6fcfdb514 Feat: dev name 2026-03-25 02:58:16 +01:00
TrèsAbhi 9df1800e10 Merge pull request #224 from karelpak1/fix-techtree
fix: include non-tier1 roots in tank tech tree routes
2026-03-24 19:31:46 -05:00
TrèsAbhi 95ba925d27 Merge pull request #226 from karelpak1/fix-yaw-pitch-inputs
fix: initialize tank quick inputs from current model transform
2026-03-24 19:29:21 -05:00
GonnaHetzMe 41882ddf23 fix: initialize tank quick inputs from current model transform 2026-03-25 01:12:06 +01:00
GonnaHetzMe fe9b543a75 fix: include non-tier1 roots in tank tech tree routes 2026-03-25 00:43:30 +01:00
TrèsAbhi 191843f972 Merge pull request #220 from blitzkit/main-i18n
New Crowdin updates
2026-03-24 09:39:43 -05:00
TrèsAbhi c1fde44809 Merge pull request #223 from blitzkit/fixes
fixes
2026-03-24 09:39:28 -05:00
TrèsAbhi 1a3517e035 feat: logs 2026-03-23 22:50:34 -05:00
TrèsAbhi afec6d9851 feat: enable all tiers 2026-03-23 22:41:34 -05:00
TrèsAbhi e3f2fd70ad fix: use turret mantlet 2026-03-23 22:36:10 -05:00
TrèsAbhi 5adbec25c4 fix: compact compare headers 2026-03-23 22:20:29 -05:00
TrèsAbhi 4ff8d77460 fix: object review videos 2026-03-23 22:13:29 -05:00
TrèsAbhi 22faa6d294 fix: stale compare indices 2026-03-23 22:07:20 -05:00
TrèsAbhi a2abfa7f85 fix: v-stabs now give 12% 2026-03-23 21:56:33 -05:00
TrèsAbhi 7b93b12fcb Merge pull request #222 from karelpak1/Position-fix 2026-03-23 19:56:17 -05:00
GonnaHetzMe ed252d5dfe Reset localTranslation for model extraction 2026-03-23 13:17:42 +01:00
TrèsAbhi c365993541 feat: remove discord bot
.
2026-03-19 09:21:58 -05:00
TrèsAbhi 30f9475208 feat: disable bot 2026-03-19 09:19:28 -05:00
TrèsAbhi 454c526666 New translations en.json (Polish) 2026-03-16 18:24:41 -05:00
TrèsAbhi e67970d2b9 New translations en.json (Polish) 2026-03-16 16:55:46 -05:00
TrèsAbhi 0f1c03d1e5 New translations en.json (Chinese Simplified) 2026-03-12 22:52:18 -05:00
tresabhi 8394f2ec1e feat: logs 2026-03-11 16:51:32 -05:00
tresabhi f14e73d811 fix: alpha clipping 2026-03-11 16:50:18 -05:00
TrèsAbhi 23e00b4199 New translations en.json (Polish) 2026-03-10 14:55:15 -05:00
TrèsAbhi 427b189a34 New Crowdin updates (#217) 2026-03-04 17:42:01 -06:00
TrèsAbhi eab4266fd1 feat: logs 2026-02-21 22:27:48 -06:00
TrèsAbhi 86b4b63a7c feat: dead commands 2026-02-21 22:26:29 -06:00
TrèsAbhi 547614fa89 fix: react versouins 2026-02-18 19:11:58 -06:00
TrèsAbhi e803d96f20 feat: lgos 2026-02-18 19:06:49 -06:00
TrèsAbhi 009caeeaf1 fix: left align filters on small screens 2026-02-18 19:00:09 -06:00
TrèsAbhi bfa80cd549 fix: optional teritery shell 2026-02-18 18:57:17 -06:00
TrèsAbhi 987c798b7e feat: increase max zoom distance 2026-02-18 18:55:38 -06:00
TrèsAbhi 8dbe7cb155 fix: short hand compare toggles 2026-02-18 18:54:23 -06:00
TrèsAbhi 053f1e3ac8 fix: ricochet visualizer doesn't drag whole page 2026-02-18 18:53:29 -06:00
TrèsAbhi 588c0a809b fix: static armor updates on thickness change 2026-02-18 18:48:59 -06:00
TrèsAbhi dde059b1f9 fix: remove debug logs 2026-02-18 18:46:41 -06:00
TrèsAbhi 102072746a fix: static armor show on deselect 2026-02-18 18:45:39 -06:00
TrèsAbhi 10d7fe1e75 feat: auto crop image 2026-02-18 18:38:40 -06:00
TrèsAbhi 4cc4e664df fix: high end consumables gives 33% extra not 70% 2026-02-18 18:22:56 -06:00
TrèsAbhi d5269e763b fix: transparency checks and depth writing 2026-02-18 18:20:37 -06:00
TrèsAbhi bae7ca2720 fix: turret angles round back to \pm 180deg 2026-02-18 18:09:05 -06:00
TrèsAbhi a0b81bfb83 bruh 2026-02-18 16:52:47 -06:00
TrèsAbhi 629e9f814e bruh 2026-02-18 16:49:08 -06:00
TrèsAbhi f39d1bab4e wait wait wait no no no 2026-02-18 16:45:06 -06:00
223 changed files with 6673 additions and 8570 deletions

No files matched your search

+4
View File
@@ -73,10 +73,14 @@ jobs:
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: Install patches
run: bun run setup:patches --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
- name: Build assets
run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
run: bun run build:bot
- name: Archive build
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: bot
path: dist/bot
-6
View File
@@ -1,13 +1,7 @@
name: Host
on:
push:
branches: main
schedule:
- cron: "0 */5 * * *"
workflow_dispatch:
release:
types: [created, published, released, edited]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
+3 -3
View File
@@ -46,14 +46,14 @@ jobs:
- uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GH_TOKEN }}
- uses: actions/configure-pages@v5
- uses: actions/configure-pages@v6
- run: bun run setup
- name: Build website
run: bun run build:website
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
uses: actions/upload-pages-artifact@v5
with:
path: dist/website
@@ -69,4 +69,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
+1
View File
@@ -17,6 +17,7 @@
"astrojs",
"astrolib",
"atgm",
"autocrop",
"Autoloader",
"Autoreloader",
"AYUV",
+140 -14
View File
@@ -6,6 +6,7 @@
"name": "blitzkit",
"dependencies": {
"@prisma/client": "^6.18.0",
"lz4js": "^0.2.0",
"prisma": "^6.18.0",
"sharp": "^0.34.5",
"typescript": "^5.9.3",
@@ -27,26 +28,26 @@
"@blitzkit/core": "workspace:*",
"@blitzkit/i18n": "workspace:*",
"@radix-ui/colors": "^3.0.0",
"@radix-ui/themes": "^3.2.1",
"@radix-ui/themes": "^3.3.0",
"@resvg/resvg-js": "^2.6.2",
"@types/adm-zip": "^0.5.7",
"@types/bun": "^1.3.9",
"@types/lodash-es": "^4.17.12",
"@types/markdown-escape": "^1.1.3",
"@types/react": "^19.2.2",
"@types/react": "^19.2.14",
"adm-zip": "^0.5.16",
"bepaint": "^0.1.0-beta.3",
"discord.js": "^14.22.1",
"dotenv": "^17.2.2",
"discord.js": "^14.25.1",
"dotenv": "^17.3.1",
"fuzzysort": "^3.1.0",
"lodash-es": "^4.17.21",
"lodash-es": "^4.17.23",
"markdown-escape": "^2.0.0",
"pickleparser": "^0.2.1",
"prisma": "^6.17.1",
"prisma": "^6.19.2",
"protobufjs": "^7.5.4",
"react": "^19.2.0",
"satori": "^0.18.3",
"sharp": "^0.34.4",
"react": "^19.2.4",
"satori": "^0.18.4",
"sharp": "^0.34.5",
},
},
"packages/closed": {
@@ -78,7 +79,6 @@
"dotenv": "^17.2.2",
"fast-xml-parser": "^5.3.2",
"lodash-es": "^4.17.21",
"lz4js": "^0.2.0",
"pickleparser": "^0.2.1",
"protobufjs": "^7.5.4",
"three": "^0.180.0",
@@ -118,7 +118,6 @@
"fast-xml-parser": "^5.2.5",
"googleapis": "^162.0.0",
"lodash-es": "^4.17.21",
"lz4js": "^0.2.0",
"progress": "^2.0.3",
"puppeteer": "^24.22.3",
"sharp": "^0.34.4",
@@ -164,12 +163,13 @@
"compare-versions": "^6.1.1",
"fuzzysort": "^3.1.0",
"immer": "^10.1.3",
"jimp": "^1.6.0",
"lodash-es": "^4.17.21",
"markdown-to-jsx": "^7.7.13",
"pwa-install-handler": "^2.6.3",
"quicklime": "^1.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-promise-suspense": "^0.3.4",
"three": "^0.180.0",
"three-stdlib": "^2.36.0",
@@ -565,6 +565,62 @@
"@img/sharp-win32-x64": ["@img/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
"@jimp/core": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="],
"@jimp/diff": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="],
"@jimp/file-ops": ["@jimp/[email protected]", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="],
"@jimp/js-bmp": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="],
"@jimp/js-gif": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="],
"@jimp/js-jpeg": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="],
"@jimp/js-png": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="],
"@jimp/js-tiff": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="],
"@jimp/plugin-blit": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="],
"@jimp/plugin-blur": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="],
"@jimp/plugin-circle": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="],
"@jimp/plugin-color": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="],
"@jimp/plugin-contain": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="],
"@jimp/plugin-cover": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="],
"@jimp/plugin-crop": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="],
"@jimp/plugin-displace": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="],
"@jimp/plugin-dither": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="],
"@jimp/plugin-fisheye": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="],
"@jimp/plugin-flip": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="],
"@jimp/plugin-hash": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="],
"@jimp/plugin-mask": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="],
"@jimp/plugin-print": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="],
"@jimp/plugin-quantize": ["@jimp/[email protected]", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="],
"@jimp/plugin-resize": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="],
"@jimp/plugin-rotate": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="],
"@jimp/plugin-threshold": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="],
"@jimp/types": ["@jimp/[email protected]", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="],
"@jimp/utils": ["@jimp/[email protected]", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="],
"@jridgewell/gen-mapping": ["@jridgewell/[email protected]", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/[email protected]", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
@@ -919,6 +975,8 @@
"@tauri-apps/plugin-opener": ["@tauri-apps/[email protected]", "", { "dependencies": { "@tauri-apps/api": "^2.8.0" } }, "sha512-B0LShOYae4CZjN8leiNDbnfjSrTwoZakqKaWpfoH6nXiJwt6Rgj6RnVIffG3DoJiKsffRhMkjmBV9VeilSb4TA=="],
"@tokenizer/token": ["@tokenizer/[email protected]", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
"@tootallnate/quickjs-emscripten": ["@tootallnate/[email protected]", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
"@tweenjs/tween.js": ["@tweenjs/[email protected]", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="],
@@ -1033,6 +1091,8 @@
"@webgpu/types": ["@webgpu/[email protected]", "", {}, "sha512-cYrHab4d6wuVvDW5tdsfI6/o6vcLMDe6w2Citd1oS51Xxu2ycLCnVo4fqwujfKWijrZMInTJIKcXxteoy21nVA=="],
"abort-controller": ["[email protected]", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"adm-zip": ["[email protected]", "", {}, "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ=="],
@@ -1047,6 +1107,8 @@
"ansi-styles": ["[email protected]", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"any-base": ["[email protected]", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="],
"anymatch": ["[email protected]", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
"argparse": ["[email protected]", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
@@ -1075,6 +1137,8 @@
"available-typed-arrays": ["[email protected]", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
"await-to-js": ["[email protected]", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="],
"axobject-query": ["[email protected]", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
"b4a": ["[email protected]", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="],
@@ -1121,6 +1185,8 @@
"bl": ["[email protected]", "", { "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww=="],
"bmp-ts": ["[email protected]", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="],
"boolbase": ["[email protected]", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
"bottleneck": ["[email protected]", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
@@ -1423,10 +1489,16 @@
"etag": ["[email protected]", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
"event-target-shim": ["[email protected]", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="],
"eventemitter3": ["[email protected]", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
"events": ["[email protected]", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
"events-universal": ["[email protected]", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="],
"exif-parser": ["[email protected]", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="],
"exsolve": ["[email protected]", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="],
"extend": ["[email protected]", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
@@ -1521,6 +1593,8 @@
"get-uri": ["[email protected]", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
"gifwrap": ["[email protected]", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
"giget": ["[email protected]", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="],
"github-slugger": ["[email protected]", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
@@ -1605,6 +1679,8 @@
"ieee754": ["[email protected]", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"image-q": ["[email protected]", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="],
"immediate": ["[email protected]", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
"immer": ["[email protected]", "", {}, "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw=="],
@@ -1709,8 +1785,12 @@
"jake": ["[email protected]", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="],
"jimp": ["[email protected]", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="],
"jiti": ["[email protected]", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ=="],
"jpeg-js": ["[email protected]", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="],
"js-tokens": ["[email protected]", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-yaml": ["[email protected]", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
@@ -1881,6 +1961,8 @@
"micromatch": ["[email protected]", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"mime": ["[email protected]", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
"mime-db": ["[email protected]", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
"mime-types": ["[email protected]", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
@@ -1941,6 +2023,8 @@
"ohash": ["[email protected]", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
"omggif": ["[email protected]", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="],
"on-finished": ["[email protected]", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
"once": ["[email protected]", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
@@ -1967,6 +2051,12 @@
"parent-module": ["[email protected]", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parse-bmfont-ascii": ["[email protected]", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="],
"parse-bmfont-binary": ["[email protected]", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="],
"parse-bmfont-xml": ["[email protected]", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="],
"parse-css-color": ["[email protected]", "", { "dependencies": { "color-name": "^1.1.4", "hex-rgb": "^4.1.0" } }, "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg=="],
"parse-json": ["[email protected]", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
@@ -1989,6 +2079,8 @@
"pathe": ["[email protected]", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"peek-readable": ["[email protected]", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="],
"pend": ["[email protected]", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
"perfect-debounce": ["[email protected]", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
@@ -2007,8 +2099,12 @@
"pinkie-promise": ["[email protected]", "", { "dependencies": { "pinkie": "^2.0.0" } }, "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw=="],
"pixelmatch": ["[email protected]", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="],
"pkg-types": ["[email protected]", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
"pngjs": ["[email protected]", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
"possible-typed-array-names": ["[email protected]", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["[email protected]", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
@@ -2025,6 +2121,8 @@
"prismjs": ["[email protected]", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
"process": ["[email protected]", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="],
"process-nextick-args": ["[email protected]", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
"progress": ["[email protected]", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
@@ -2075,7 +2173,7 @@
"react": ["[email protected]", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["[email protected].0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
"react-dom": ["[email protected].4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-promise-suspense": ["[email protected]", "", { "dependencies": { "fast-deep-equal": "^2.0.1" } }, "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ=="],
@@ -2093,6 +2191,8 @@
"readable-stream": ["[email protected]", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
"readable-web-to-node-stream": ["[email protected]", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="],
"readdirp": ["[email protected]", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"reflect.getprototypeof": ["[email protected]", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
@@ -2211,6 +2311,8 @@
"simple-swizzle": ["[email protected]", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="],
"simple-xml-to-json": ["[email protected]", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="],
"sisteransi": ["[email protected]", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
"smart-buffer": ["[email protected]", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
@@ -2279,6 +2381,8 @@
"strnum": ["[email protected]", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
"strtok3": ["[email protected]", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="],
"supports-preserve-symlinks-flag": ["[email protected]", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"suspend-react": ["[email protected]", "", { "peerDependencies": { "react": ">=17.0" } }, "sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ=="],
@@ -2307,6 +2411,8 @@
"tiny-typed-emitter": ["[email protected]", "", {}, "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="],
"tinycolor2": ["[email protected]", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="],
"tinyexec": ["[email protected]", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
"tinyglobby": ["[email protected]", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
@@ -2317,6 +2423,8 @@
"toidentifier": ["[email protected]", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
"token-types": ["[email protected]", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="],
"tr46": ["[email protected]", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="],
"trim-lines": ["[email protected]", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
@@ -2437,6 +2545,8 @@
"use-sync-external-store": ["[email protected]", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
"utif2": ["[email protected]", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="],
"util-deprecate": ["[email protected]", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
"utility-types": ["[email protected]", "", {}, "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw=="],
@@ -2565,6 +2675,8 @@
"ws": ["[email protected]", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"xml-parse-from-string": ["[email protected]", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="],
"xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="],
"xmlbuilder": ["[email protected]", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
@@ -2639,6 +2751,8 @@
"@discordjs/ws/discord-api-types": ["[email protected]", "", {}, "sha512-xpmPviHjIJ6dFu1eNwNDIGQ3N6qmPUUYFVAx/YZ64h7ZgPkTcKjnciD8bZe8Vbeji7yS5uYljyciunpq0J5NSw=="],
"@jimp/core/file-type": ["[email protected]", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="],
"@octokit/endpoint/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
"@octokit/graphql/@octokit/types": ["@octokit/[email protected]", "", { "dependencies": { "@octokit/openapi-types": "^25.1.0" } }, "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g=="],
@@ -2715,6 +2829,8 @@
"https-proxy-agent/agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"image-q/@types/node": ["@types/[email protected]", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="],
"its-fine/@types/react-reconciler": ["@types/[email protected]", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg=="],
"linebreak/base64-js": ["[email protected]", "", {}, "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw=="],
@@ -2729,8 +2845,12 @@
"pac-proxy-agent/socks-proxy-agent": ["[email protected]", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
"parse-bmfont-xml/xml2js": ["[email protected]", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="],
"parse5/entities": ["[email protected]", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"pixelmatch/pngjs": ["[email protected]", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="],
"prompts/kleur": ["[email protected]", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"proxy-agent/agent-base": ["[email protected]", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
@@ -2745,6 +2865,8 @@
"readable-stream/safe-buffer": ["[email protected]", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
"readable-web-to-node-stream/readable-stream": ["[email protected]", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
"safe-array-concat/isarray": ["[email protected]", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"safe-push-apply/isarray": ["[email protected]", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
@@ -2783,6 +2905,8 @@
"unicode-trie/pako": ["[email protected]", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="],
"utif2/pako": ["[email protected]", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
"volar-service-typescript/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"vscode-json-languageservice/jsonc-parser": ["[email protected]", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
@@ -2979,6 +3103,8 @@
"ndarray-pixels/sharp/semver": ["[email protected]", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"readable-web-to-node-stream/readable-stream/string_decoder": ["[email protected]", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
"steam-appticket/protobufjs/@types/long": ["@types/[email protected]", "", {}, "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="],
"steam-appticket/protobufjs/long": ["[email protected]", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="],
+5
View File
@@ -0,0 +1,5 @@
{
"words": [
"Tankopedia"
]
}
+20
View File
@@ -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
+11
View File
@@ -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`
+5
View File
@@ -0,0 +1,5 @@
# BlitzKit 1.29.15
## Fixes
- Tanks now use alpha clipping to render translucency, fixing a lot of "ghostly" looking tanks
+18
View File
@@ -0,0 +1,18 @@
# BlitzKit 1.29.16
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
## Fixes
- [GonnaHetzMe] The turret for Centurion I is no longer offset from the body
- Please allow up to 24 hours for the model to update
- Vertical Stabilizers now give the correct 12% buff instead of 15%
- Re-ordering tanks in Compare now works once again
- Fixed review videos from being about the Object 452K across all tanks
- Please allow up to 2 weeks for all tanks to refresh their videos
- Tanks in Mixer with oscillating turrets are not handled properly
## Features
- Headings in the Compare tool are now even more compact for mobile devices
- Enabled all tiers for the randomizer in Mixer
+23
View File
@@ -0,0 +1,23 @@
# BlitzKit 1.30.0
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
## Features
- Added an equalizer mode for Tankopedia and Compare to preview what tank stats will look like in the upcoming Equalizer game mode
- This feature is in Beta and the stats are subject to change
- Thanks to WoTB News for sourcing data well ahead of the release of the gamemode
- Added a toggle in Tankopedia, right beneath Provisions
- Added button under the shell selector in the Tank Sandbox
- Added another toggle in the Compare table to enable equalizer for all tanks
## Technical Features
- [GonnaHetzMe] Enabling dev mode now displays the tank's non-numerical id
- [GonnaHetzMe] The dev id and the new dev name are now copyable on click
## Fixes
- [GonnaHetzMe] Tech trees that start at tiers higher than tier 1 like the Blitz Nation ones now properly render their trees in Tankopedia
- [GonnaHetzMe] The tank pitch/yaw inputs in the Tank Sandbox now initialize with the correct values instead of 0
- [GonnaHetzMe] Large Repair Kits once again use the correct modern icon
+8
View File
@@ -0,0 +1,8 @@
# BlitzKit 1.30.1
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
## Fixes
- [GonnaHetzMe] Tank hit points in Equalizer mode is now accurate to the game
- Armor highlighting now reflects the actual thicknesses of tanks in Equalizer mode
+12
View File
@@ -0,0 +1,12 @@
# BlitzKit 1.30.2
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
## Fixes
- [GonnaHetzMe] Tungsten shells are now properly cropped
- Equalizer no longer gives insanely high penetration values
- The tank reveal animation no longer repeats when you scroll away and back to the tank sandbox
- [GonnaHetzMe] The RHM. Pzw.'s turret no longer has the floating plate
- Please give BlitzKit up to 1 hour to update the model
- [GonnaHetzMe] Tanks with inclined turret rings like the Minotauro now display the correct pitch in the tank sandbox inputs
+18
View File
@@ -0,0 +1,18 @@
# BlitzKit 1.30.3
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
## Features
- [GonnaHetzMe] Added tooltips to the module selector in Tankopedia
## Fixes
- Added aggressive re-rendering for the Guess mini-game's score readout to make inspect-element harder
- Removed tank visual and collision model caching
- Guesser once again breaks streaks if not all tiers are selected
- BlitzKit now properly unloads tank models from memory when visually hidden in Guesser
- [GonnaHetzMe] Tanks with complex transparency like the Herdbreaker once again handle opacity correctly
- [GonnaHetzMe] Pieces of tank models that have transparency now handle culling properly (they're visible from both sides)
- [GonnaHetzMe] Tanks with "cardboard" textures have been fixed, thanks to better PVR file parsing
- [GonnaHetzMe] Tank icons are now scaled correctly so small tanks are now properly zoomed out in contrast to bigger ones
+5
View File
@@ -0,0 +1,5 @@
# BlitzKit 1.30.4
## Fixes
- BlitzKit now correctly implements minor WoTB updates
+8
View File
@@ -0,0 +1,8 @@
# BlitzKit 1.30.5
## Features
- Reduced the amount of code that executes for every rendered frame, hopefully improving performance
- Reduced the number of lights by 20% to decrease the amount of shadow calculations
- Decreased the ground size by 80% for an equal reduction in shadow texture sizes
- Added the ability for BlitzKit to dismount the components that handled the intro lighting animation when not animating, reducing checks running every frame
+7
View File
@@ -0,0 +1,7 @@
# BlitzKit 1.30.6
## Fixes
- Tanks no longer "randomly" appear dark in Tankopedia and Mixer
- The ground is now as dark as other modes when Static Armor is selected in Tankopedia
- Fixed some naming issues with the "equal" icon, improving performance a tiny tiny bit
+20
View File
@@ -0,0 +1,20 @@
# BlitzKit 1.30.7
Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update.
## Features
- Dragging items in the Tier List now automatically scrolls the screen if you reach the top/bottom edge of the screen
## Fixes
- [Mark Greene] Clicking on the armor multiple times with HE no longer crashes BlitzKit
- [Mark Greene] Ricochets that later intersect with external modules no longer falsely claim a successful damaging penetration
- The lighting animation no longer stops prematurely when BlitzKit is unfocused
- The spot light angle has been increased to more evenly light up larger tanks
- BlitzKit once again uses soft shadows, reducing the pixelated shadows
- Fixed the weird patterns that formed on the tracks of tanks under self-shadows
- Increased the floor size and light decay to create the illusion that the floor is infinite
- [Mark Greene] Safari no longer crashes when unloading textures for unloaded tanks
- The gun depression transition between two constraints (like often behind tanks) now uses a gentler zoned and can never be 0
- [Mark Greene] Armor plate names in Static Armor are now properly capitalized in English and translated to other languages
+4 -3
View File
@@ -1,6 +1,6 @@
{
"name": "blitzkit",
"version": "1.29.12",
"version": "1.30.7",
"license": "BlitzKit License",
"private": true,
"scripts": {
@@ -21,7 +21,7 @@
"dev": "bun run dev:website",
"dev:api": "bun --filter=@blitzkit/api run dev",
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
"setup:patches": "mkdir -p packages/closed/node_modules && ln -sf ../../../node_modules/lz4js packages/closed/node_modules/lz4js && cd packages/scripts && bun run setup:patches",
"start:website": "bun --filter=@blitzkit/website run start",
"host:docs": "vitepress preview docs",
"lint": "tsc",
@@ -35,7 +35,7 @@
"build:reviews": "cd packages/scripts && bun build:reviews",
"build:ids": "cd packages/scripts && bun build:ids",
"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",
"patchnotes": "cd packages/scripts && bun run patchnotes"
},
"type": "module",
@@ -44,6 +44,7 @@
],
"dependencies": {
"@prisma/client": "^6.18.0",
"lz4js": "^0.2.0",
"prisma": "^6.18.0",
"sharp": "^0.34.5",
"typescript": "^5.9.3"
+33 -36
View File
@@ -1,49 +1,46 @@
import { getBlitzStarsLinkButton } from '../../core/blitzstars/getBlitzStarsLinkButton';
import { addPeriodicFilterOptions } from '../../core/discord/addPeriodicFilterOptions';
import { addUsernameChoices } from '../../core/discord/addUsernameChoices';
import { autocompleteTanks } from '../../core/discord/autocompleteTanks';
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 { getCustomPeriodParams } from '../../core/discord/getCustomPeriodParams';
import { getFiltersFromButton } from '../../core/discord/getFiltersFromButton';
import { getFiltersFromCommand } from '../../core/discord/getFiltersFromCommand';
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';
import { addPeriodicFilterOptions } from "../../core/discord/addPeriodicFilterOptions";
import { addUsernameChoices } from "../../core/discord/addUsernameChoices";
import { autocompleteTanks } from "../../core/discord/autocompleteTanks";
import { autocompleteUsername } from "../../core/discord/autocompleteUsername";
import { createLocalizedCommand } from "../../core/discord/createLocalizedCommand";
import { getFiltersFromButton } from "../../core/discord/getFiltersFromButton";
import { resolvePeriodFromButton } from "../../core/discord/resolvePeriodFromButton";
import { resolvePlayerFromButton } from "../../core/discord/resolvePlayerFromButton";
import { translator } from "../../core/localization/translator";
import type { CommandRegistry } from "../../events/interactionCreate";
import { renderBreakdown } from "./render";
export const breakdownCommand = new Promise<CommandRegistry>(
async (resolve) => {
resolve({
command: await addPeriodicFilterOptions(
createLocalizedCommand('breakdown'),
createLocalizedCommand("breakdown"),
(option) => option.addStringOption(addUsernameChoices),
),
async handler(interaction) {
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const filters = await getFiltersFromCommand(interaction);
const path = commandToURL(interaction, {
...player,
...getCustomPeriodParams(interaction),
...filters,
});
const { strings } = translator(interaction.locale);
return strings.bot.commands.dead;
return [
...(await renderBreakdown(
player,
period,
filters,
interaction.locale,
)),
buttonRefresh(interaction, path),
await getBlitzStarsLinkButton(player.region, player.id),
];
// const player = await resolvePlayerFromCommand(interaction);
// const period = resolvePeriodFromCommand(player.region, interaction);
// const filters = await getFiltersFromCommand(interaction);
// const path = commandToURL(interaction, {
// ...player,
// ...getCustomPeriodParams(interaction),
// ...filters,
// });
// return [
// ...(await renderBreakdown(
// player,
// period,
// filters,
// interaction.locale,
// )),
// buttonRefresh(interaction, path),
// await getBlitzStarsLinkButton(player.region, player.id),
// ];
},
autocomplete: (interaction) => {
+41 -48
View File
@@ -5,8 +5,6 @@ import * as Graph from "../components/Graph";
import { LineColor } from "../components/Graph/components/Line/constants";
import { NoData } from "../components/NoData";
import { TitleBar } from "../components/TitleBar";
import { resolveTankId } from "../core/blitz/resolveTankId";
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
import { getPlayerHistories } from "../core/blitzstars/getPlayerHistories";
import { getTankHistories } from "../core/blitzstars/getTankHistories";
import { addPeriodSubCommands } from "../core/discord/addPeriodSubCommands";
@@ -14,20 +12,12 @@ import { addTankChoices } from "../core/discord/addTankChoices";
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
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 { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
import {
type ResolvedPeriod,
resolvePeriodFromCommand,
} from "../core/discord/resolvePeriodFromCommand";
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
import {
type ResolvedPlayer,
resolvePlayerFromCommand,
} from "../core/discord/resolvePlayerFromCommand";
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
import { translator } from "../core/localization/translator";
import type { CommandRegistry } from "../events/interactionCreate";
type EvolutionStatType = "player" | "tank";
@@ -37,7 +27,7 @@ async function render(
{ start, end, name }: ResolvedPeriod,
type: "player" | "tank",
tankId: number | null,
locale: Locale
locale: Locale,
) {
const accountInfo = await getAccountInfo(region, id);
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
@@ -61,7 +51,7 @@ async function render(
[
history.all.battles,
(history.all.wins / history.all.battles) * 100,
] as Graph.PlotItem
] as Graph.PlotItem,
);
const times = histories.map((history) => history.last_battle_time);
const minTime = Math.min(...times);
@@ -115,7 +105,7 @@ export const evolutionCommand = new Promise<CommandRegistry>(
group: "player",
modify(option: SlashCommandSubcommandGroupBuilder) {
addPeriodSubCommands(option, (option) =>
option.addStringOption(addUsernameChoices)
option.addStringOption(addUsernameChoices),
);
},
},
@@ -125,43 +115,46 @@ export const evolutionCommand = new Promise<CommandRegistry>(
addPeriodSubCommands(option, (option) =>
option
.addStringOption(addTankChoices)
.addStringOption(addUsernameChoices)
.addStringOption(addUsernameChoices),
);
},
},
]),
async handler(interaction) {
const commandGroup =
interaction.options.getSubcommandGroup() as EvolutionStatType;
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,
});
const { strings } = translator(interaction.locale);
return strings.bot.commands.dead;
return [
await render(
player,
period,
commandGroup,
tankId,
interaction.locale
),
buttonRefresh(interaction, path),
await getBlitzStarsLinkButton(
player.region,
player.id,
tankId ?? undefined
),
];
// const commandGroup =
// interaction.options.getSubcommandGroup() as EvolutionStatType;
// 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 [
// await render(
// player,
// period,
// commandGroup,
// tankId,
// interaction.locale
// ),
// buttonRefresh(interaction, path),
// await getBlitzStarsLinkButton(
// player.region,
// player.id,
// tankId ?? undefined
// ),
// ];
},
autocomplete: (interaction) => {
@@ -181,9 +174,9 @@ export const evolutionCommand = new Promise<CommandRegistry>(
period,
commandGroup,
parseInt(url.searchParams.get("tankId") ?? "0") || null,
interaction.locale
interaction.locale,
);
},
});
}
},
);
+40 -47
View File
@@ -3,38 +3,28 @@ import {
getAccountInfo,
getClanAccountInfo,
getTierWeights,
} from '@blitzkit/core';
import { Locale } from 'discord.js';
import { CommandWrapper } from '../components/CommandWrapper';
import { GenericAllStats } from '../components/GenericAllStats';
import { NoData } from '../components/NoData';
import { TierWeights } from '../components/TierWeights';
import { TitleBar } from '../components/TitleBar';
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
import { filterStats, type StatFilters } from '../core/blitzstars/filterStats';
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
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 { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
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';
} from "@blitzkit/core";
import { Locale } from "discord.js";
import { CommandWrapper } from "../components/CommandWrapper";
import { GenericAllStats } from "../components/GenericAllStats";
import { NoData } from "../components/NoData";
import { TierWeights } from "../components/TierWeights";
import { TitleBar } from "../components/TitleBar";
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
import { translator } from "../core/localization/translator";
import type { CommandRegistry } from "../events/interactionCreate";
async function render(
{ region, id }: ResolvedPlayer,
@@ -43,7 +33,7 @@ async function render(
locale: Locale,
) {
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 diffedTankStats = await getStatsInPeriod(
region,
@@ -86,25 +76,28 @@ export const fullStatsCommand = new Promise<CommandRegistry>(
async (resolve) => {
resolve({
command: await addPeriodicFilterOptions(
createLocalizedCommand('full-stats'),
createLocalizedCommand("full-stats"),
(option) => option.addStringOption(addUsernameChoices),
),
async handler(interaction) {
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const filters = await getFiltersFromCommand(interaction);
const path = commandToURL(interaction, {
...player,
...getCustomPeriodParams(interaction),
...filters,
});
const { strings } = translator(interaction.locale);
return strings.bot.commands.dead;
return Promise.all([
render(player, period, filters, interaction.locale),
buttonRefresh(interaction, path),
getBlitzStarsLinkButton(player.region, player.id),
]);
// const player = await resolvePlayerFromCommand(interaction);
// const period = resolvePeriodFromCommand(player.region, interaction);
// const filters = await getFiltersFromCommand(interaction);
// 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) => {
+4 -4
View File
@@ -43,7 +43,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
tankStats.map(async (tankData) => ({
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
id: tankData.tank_id,
}))
})),
)
).filter((tank) => tank.tankDefinitions?.tier === tier);
const groupedTanks: Record<string, TankDefinition[]> = {};
@@ -69,16 +69,16 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
.filter((tank) => tank.tier === tier)
.sort(
(a, b) =>
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class)
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
)
.sort(
(a, b) =>
awaitedGameDefinitions.nations.indexOf(a.nation) -
awaitedGameDefinitions.nations.indexOf(b.nation)
awaitedGameDefinitions.nations.indexOf(b.nation),
)
.map(
(tank) =>
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name!))}](<https://blitzkit.app/tanks/${tank.slug}>)`,
);
const lines = [title, ...tankList];
+2 -2
View File
@@ -280,7 +280,7 @@ async function playerListing(
}}
>
<img
alt={unwrap(tank.name)}
alt={unwrap(tank.name!)}
src={await iconPng(tankIcon(tank.id))}
style={{
width: 32,
@@ -317,7 +317,7 @@ async function playerListing(
fontSize: 16,
}}
>
{unwrap(tank.name)}
{unwrap(tank.name!)}
</span>
</div>
+47 -47
View File
@@ -35,49 +35,49 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
command: createLocalizedCommand("research")
.addStringOption((option) =>
option
.setName(strings.bot.commands.research.options.target_tank.name)
.setName(strings.bot.commands.research.options.target_tank.name!)
.setNameLocalizations(
localizationObject(
(strings) =>
strings.bot.commands.research.options.target_tank.name,
undefined,
true
)
true,
),
)
.setDescription(
strings.bot.commands.research.options.target_tank.description
strings.bot.commands.research.options.target_tank.description,
)
.setDescriptionLocalizations(
localizationObject(
(strings) =>
strings.bot.commands.research.options.target_tank.description
)
strings.bot.commands.research.options.target_tank.description,
),
)
.setAutocomplete(true)
.setRequired(true)
.setRequired(true),
)
.addStringOption((option) =>
option
.setName(strings.bot.commands.research.options.starting_tank.name)
.setName(strings.bot.commands.research.options.starting_tank.name!)
.setNameLocalizations(
localizationObject(
(strings) =>
strings.bot.commands.research.options.starting_tank.name,
undefined,
true
)
true,
),
)
.setDescription(
strings.bot.commands.research.options.starting_tank.description
strings.bot.commands.research.options.starting_tank.description,
)
.setDescriptionLocalizations(
localizationObject(
(strings) =>
strings.bot.commands.research.options.starting_tank.description
)
strings.bot.commands.research.options.starting_tank.description,
),
)
.setAutocomplete(true)
.setRequired(false)
.setRequired(false),
)
.addStringOption(addUsernameChoices),
@@ -87,7 +87,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
const targetTankId = await resolveTankId(
interaction.options.getString("target-tank", true),
interaction.locale,
true
true,
);
const startingTankRaw = interaction.options.getString("starting-tank");
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
@@ -99,13 +99,13 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
startingTankId = await resolveTankId(
startingTankRaw,
interaction.locale,
true
true,
);
if (targetTankId === startingTankId) {
return literals(
strings.bot.commands.research.errors.start_end_equal,
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
{ tank: escapeMarkdown(unwrap(targettank.name!)) },
);
}
@@ -113,8 +113,8 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
if (startingTank.tier > targetTank.tier) {
return literals(strings.bot.commands.research.errors.unordered, {
tank_1: escapeMarkdown(unwrap(startingTank.name)),
tank_2: escapeMarkdown(unwrap(targetTank.name)),
tank_1: escapeMarkdown(unwrap(startingtank.name!)),
tank_2: escapeMarkdown(unwrap(targettank.name!)),
});
}
@@ -122,21 +122,21 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
return literals(
strings.bot.commands.research.errors.tanks_not_on_line,
{
tank_1: escapeMarkdown(unwrap(targetTank.name)),
tank_2: escapeMarkdown(unwrap(startingTank.name)),
}
tank_1: escapeMarkdown(unwrap(targettank.name!)),
tank_2: escapeMarkdown(unwrap(startingtank.name!)),
},
);
}
} else {
if (targetTank.type !== TankType.RESEARCHABLE) {
if (targetTank.type !== TankType.TANK_TYPE_RESEARCHABLE) {
return literals(strings.bot.commands.research.errors.non_tech_tree, {
tank: escapeMarkdown(unwrap(targetTank.name)),
tank: escapeMarkdown(unwrap(targettank.name!)),
});
}
if (targetTank.tier === 1) {
return literals(strings.bot.commands.research.errors.tier_1, {
tank: escapeMarkdown(unwrap(targetTank.name)),
tank: escapeMarkdown(unwrap(targettank.name!)),
});
}
@@ -149,14 +149,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
return literals(
strings.bot.commands.research.errors.already_researched,
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
{ tank: escapeMarkdown(unwrap(targettank.name!)) },
);
}
const foundAncestor = targetTankAncestry.find(
(id) =>
awaitedTankDefinitions.tanks[id].tier === 1 ||
tankStats.some(({ tank_id }) => tank_id === id)
tankStats.some(({ tank_id }) => tank_id === id),
);
if (foundAncestor === undefined) {
@@ -168,7 +168,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
const techTreeLine = await buildTechTreeLine(
startingTankId,
targetTankId
targetTankId,
);
const line = [...techTreeLine, startingTankId].reverse();
@@ -190,7 +190,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
) {
turretXps.set(
turret.id,
turret.research_cost.research_cost_type!.value
turret.research_cost.research_cost_type!.value,
);
}
@@ -211,7 +211,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
) {
engineXps.set(
engine.id,
engine.research_cost.research_cost_type!.value
engine.research_cost.research_cost_type!.value,
);
}
});
@@ -223,7 +223,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
) {
trackXps.set(
track.id,
track.research_cost.research_cost_type!.value
track.research_cost.research_cost_type!.value,
);
}
});
@@ -245,13 +245,13 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
return {
research: tank.research_cost!.research_cost_type!.value as number,
upgrades: moduleXp,
purchase: tank.price.value,
purchase: tank.price!.value,
equipment: equipmentPriceMatrix[tank.tier].reduce(
(a, b) => a + 3 * b,
0
0,
),
};
})
}),
);
const image = (
@@ -456,7 +456,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
}}
>
<img
alt={unwrap(tank.name)}
alt={unwrap(tank.name!)}
src={TANK_ICONS[tank.class]}
width={16}
height={16}
@@ -467,7 +467,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
color: theme.colors.textHighContrast,
}}
>
{unwrap(tank.name)}
{unwrap(tank.name!)}
</span>
</div>
</div>
@@ -505,9 +505,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
strings.bot.commands.research.body.research,
{
cost: costs[index].research?.toLocaleString(
interaction.locale
interaction.locale,
),
}
},
)}
</span>
</div>
@@ -523,7 +523,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
<img
alt="Free XP icon"
src={await iconPng(
asset("icons/currencies/free-xp.webp")
asset("icons/currencies/free-xp.webp"),
)}
width={16}
height={16}
@@ -536,7 +536,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
>
{literals(
strings.bot.commands.research.body.upgrades,
{ cost: costs[index].upgrades.toLocaleString() }
{ cost: costs[index].upgrades.toLocaleString() },
)}
</span>
</div>
@@ -552,7 +552,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
<img
alt="Silver icon"
src={await iconPng(
asset("icons/currencies/silver.webp")
asset("icons/currencies/silver.webp"),
)}
width={16}
height={16}
@@ -567,9 +567,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
strings.bot.commands.research.body.purchase,
{
cost: costs[index].purchase.toLocaleString(
interaction.locale
interaction.locale,
),
}
},
)}
</span>
</div>
@@ -584,7 +584,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
<img
alt="Silver icon"
src={await iconPng(
asset("icons/currencies/silver.webp")
asset("icons/currencies/silver.webp"),
)}
width={16}
height={16}
@@ -599,16 +599,16 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
strings.bot.commands.research.body.equipment,
{
cost: costs[index].equipment.toLocaleString(
interaction.locale
interaction.locale,
),
}
},
)}
</span>
</div>
</div>
</div>
);
})
}),
)}
</div>
</CommandWrapper>
+22 -29
View File
@@ -6,35 +6,25 @@ import { NoData } from "../components/NoData";
import { TitleBar } from "../components/TitleBar";
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
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 { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
import { getFiltersFromCommand } from "../core/discord/getFiltersFromCommand";
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
import {
type ResolvedPeriod,
resolvePeriodFromCommand,
} from "../core/discord/resolvePeriodFromCommand";
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
import {
type ResolvedPlayer,
resolvePlayerFromCommand,
} from "../core/discord/resolvePlayerFromCommand";
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
import { translator } from "../core/localization/translator";
import type { CommandRegistry } from "../events/interactionCreate";
async function render(
{ region, id }: ResolvedPlayer,
{ start, end, name }: ResolvedPeriod,
filters: StatFilters,
locale: Locale
locale: Locale,
) {
const { nickname } = await getAccountInfo(region, id);
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
@@ -44,7 +34,7 @@ async function render(
id,
start,
end,
locale
locale,
);
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
const filterDescriptions = await filtersToDescription(filters, locale);
@@ -73,24 +63,27 @@ export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
resolve({
command: await addPeriodicFilterOptions(
createLocalizedCommand("stats"),
(option) => option.addStringOption(addUsernameChoices)
(option) => option.addStringOption(addUsernameChoices),
),
async handler(interaction) {
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(player.region, interaction);
const filters = await getFiltersFromCommand(interaction);
const path = commandToURL(interaction, {
...player,
...getCustomPeriodParams(interaction),
...filters,
});
const { strings } = translator(interaction.locale);
return strings.bot.commands.dead;
return Promise.all([
render(player, period, filters, interaction.locale),
buttonRefresh(interaction, path),
getBlitzStarsLinkButton(player.region, player.id),
]);
// const player = await resolvePlayerFromCommand(interaction);
// const period = resolvePeriodFromCommand(player.region, interaction);
// const filters = await getFiltersFromCommand(interaction);
// 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) => {
+33 -36
View File
@@ -1,50 +1,47 @@
import { gameDefinitions } from '../core/blitzkit/nonBlockingPromises';
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
import { addFilterOptions } from '../core/discord/addFilterOptions';
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
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 { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
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';
import { gameDefinitions } from "../core/blitzkit/nonBlockingPromises";
import { addFilterOptions } from "../core/discord/addFilterOptions";
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
import { translator } from "../core/localization/translator";
import { type CommandRegistry } from "../events/interactionCreate";
import { renderBreakdown } from "./breakdown/render";
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
const awaitedGameDefinitions = await gameDefinitions;
resolve({
command: addFilterOptions(
createLocalizedCommand('today'),
createLocalizedCommand("today"),
awaitedGameDefinitions.nations,
).addStringOption(addUsernameChoices),
async handler(interaction) {
const player = await resolvePlayerFromCommand(interaction);
const period = resolvePeriodFromCommand(
player.region,
interaction,
'today',
);
const filters = await getFiltersFromCommand(interaction);
const path = commandToURL(interaction, {
...player,
...getCustomPeriodParams(interaction, true),
...filters,
});
const { strings } = translator(interaction.locale);
return strings.bot.commands.dead;
return [
...(await renderBreakdown(player, period, filters, interaction.locale)),
buttonRefresh(interaction, path),
await getBlitzStarsLinkButton(player.region, player.id),
];
// const player = await resolvePlayerFromCommand(interaction);
// const period = resolvePeriodFromCommand(
// player.region,
// 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) => {
@@ -3,14 +3,14 @@ import {
TankClass,
TankType,
TREE_TYPE_ICONS,
} from '@blitzkit/core';
import { createColors } from 'bepaint';
} from "@blitzkit/core";
import { createColors } from "bepaint";
import {
type AccentColor,
type GrayColor,
PALETTES,
} from '../../../core/radix/radixColors';
import { RowStat } from './RowStat';
} from "../../../core/radix/radixColors";
import { RowStat } from "./RowStat";
export interface RowStatItem {
title: string;
@@ -21,7 +21,7 @@ export interface RowStatItem {
}
interface RowProps {
displayType?: 'tank' | 'summary';
displayType?: "tank" | "summary";
naked?: boolean;
title: string;
minimized?: boolean;
@@ -32,7 +32,7 @@ interface RowProps {
}
export function Row({
color = 'slate',
color = "slate",
stats,
title,
minimized,
@@ -49,20 +49,20 @@ export function Row({
className="session-tracker-row"
style={{
maxWidth: naked ? 600 : Infinity,
display: 'flex',
flexDirection: 'column',
display: "flex",
flexDirection: "column",
borderRadius: 4,
backgroundColor: naked
? `${theme.appBackground2}c0`
: theme.appBackground2,
overflow: 'hidden',
overflow: "hidden",
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: 8,
gap: 4,
backgroundColor: naked
@@ -70,10 +70,14 @@ export function Row({
: theme.componentInteractive,
}}
>
{displayType === 'tank' && tankClass !== undefined && (
{displayType === "tank" && tankClass !== undefined && (
<img
alt={TankClass[tankClass]}
src={TREE_TYPE_ICONS[type ?? TankType.RESEARCHABLE][tankClass]}
src={
TREE_TYPE_ICONS[type ?? TankType.TANK_TYPE_RESEARCHABLE][
tankClass
]
}
style={{ width: 16, height: 16 }}
/>
)}
@@ -81,10 +85,10 @@ export function Row({
<span
style={{
color:
displayType === 'tank'
? type === TankType.COLLECTOR
displayType === "tank"
? type === TankType.TANK_TYPE_COLLECTOR
? theme.textLowContrast_blue
: type === TankType.PREMIUM
: type === TankType.TANK_TYPE_PREMIUM
? theme.textLowContrast_amber
: theme.textHighContrast
: theme.textLowContrast,
@@ -98,7 +102,7 @@ export function Row({
<div
style={{
display: 'flex',
display: "flex",
paddingTop: 8,
paddingBottom: 8,
}}
@@ -109,8 +113,8 @@ export function Row({
<RowStat
minimized={minimized}
key={index}
name={`${row.title} • ${row.career ?? '--'}`}
value={row.current ?? '--'}
name={`${row.title} • ${row.career ?? "--"}`}
value={row.current ?? "--"}
delta={row.delta}
percentile={row.percentile}
/>
@@ -1,5 +1,5 @@
import { TankClass, TankType, TREE_TYPE_ICONS } from '@blitzkit/core';
import { theme } from '../../../../stitches.config';
import { TankClass, TankType, TREE_TYPE_ICONS } from "@blitzkit/core";
import { theme } from "../../../../stitches.config";
export interface ItemProps {
tankClass?: TankClass;
@@ -8,9 +8,9 @@ export interface ItemProps {
}
const TREE_TYPE_COLOR = {
[TankType.RESEARCHABLE]: '',
[TankType.PREMIUM]: '_amber',
[TankType.COLLECTOR]: '_blue',
[TankType.TANK_TYPE_RESEARCHABLE]: "",
[TankType.TANK_TYPE_PREMIUM]: "_amber",
[TankType.TANK_TYPE_COLLECTOR]: "_blue",
} as const;
export function Item({
@@ -21,12 +21,12 @@ export function Item({
return (
<div
style={{
display: 'flex',
display: "flex",
height: 32,
paddingLeft: 8,
paddingRight: 8,
overflow: 'hidden',
alignItems: 'center',
overflow: "hidden",
alignItems: "center",
borderRadius: 4,
backgroundColor:
theme.colors[`componentInteractive${TREE_TYPE_COLOR[treeType]}`],
@@ -34,12 +34,12 @@ export function Item({
>
<div
style={{
display: 'flex',
display: "flex",
gap: 4,
flex: 1,
alignItems: 'center',
justifyContent: 'flex-start',
overflow: 'hidden',
alignItems: "center",
justifyContent: "flex-start",
overflow: "hidden",
}}
>
{tankType && (
@@ -52,7 +52,7 @@ export function Item({
<span
style={{
fontSize: 16,
whiteSpace: 'nowrap',
whiteSpace: "nowrap",
color: theme.colors[`textLowContrast${TREE_TYPE_COLOR[treeType]}`],
}}
>
@@ -6,21 +6,21 @@ import { translator } from "../localization/translator";
export async function filtersToDescription(
{ nation, tier, type, class: tankClass, tank }: StatFilters,
locale: Locale
locale: Locale,
) {
const { strings, bkLocale } = translator(locale);
const awaitedTankDefinitions = await fetchTankDefinitions();
const info: string[] = [];
// TODO: somehow localize tank names?
if (tank) return awaitedTankDefinitions.tanks[tank].name.locales[bkLocale];
if (tank) return awaitedTankDefinitions.tanks[tank].name!.locales[bkLocale];
if (nation)
info.push((strings.common.nations as Record<string, string>)[nation]);
if (tier) {
info.push(
literals(strings.bot.common.filters.tier, {
tier: TIER_ROMAN_NUMERALS[tier],
})
}),
);
}
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
@@ -34,12 +34,12 @@ export async function filterStats(
(filters.tier === undefined || entry.tier === filters.tier) &&
(filters.class === undefined || entry.class === filters.class) &&
(filters.type === undefined ||
(filters.type === TankType.COLLECTOR &&
entry.type === TankType.COLLECTOR) ||
(filters.type === TankType.PREMIUM &&
entry.type === TankType.PREMIUM) ||
(filters.type === TankType.RESEARCHABLE &&
entry.type === TankType.RESEARCHABLE)) &&
(filters.type === TankType.TANK_TYPE_COLLECTOR &&
entry.type === TankType.TANK_TYPE_COLLECTOR) ||
(filters.type === TankType.TANK_TYPE_PREMIUM &&
entry.type === TankType.TANK_TYPE_PREMIUM) ||
(filters.type === TankType.TANK_TYPE_RESEARCHABLE &&
entry.type === TankType.TANK_TYPE_RESEARCHABLE)) &&
(filters.tank === undefined || entry.id === filters.tank)
);
});
@@ -1,12 +1,12 @@
import { Locale, SlashCommandStringOption } from 'discord.js';
import { translator } from '../localization/translator';
import { localizationObject } from './localizationObject';
import { Locale, SlashCommandStringOption } from "discord.js";
import { translator } from "../localization/translator";
import { localizationObject } from "./localizationObject";
export function addTankChoices(option: SlashCommandStringOption) {
const { strings } = translator(Locale.EnglishUS);
return option
.setName(strings.bot.common.options.tank.name)
.setName(strings.bot.common.options.tank.name!)
.setNameLocalizations(
localizationObject(
(strings) => strings.bot.common.options.tank.name,
@@ -13,13 +13,13 @@ import {
} from "./autocompleteClan/constants";
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE)
names.filter((tank) => tank.treeType === TankType.TANK_TYPE_RESEARCHABLE),
);
export async function autocompleteTanks(
interaction: AutocompleteInteraction<CacheType>,
techTreeOnly = false,
fields = ["tank"]
fields = ["tank"],
) {
const { unwrap } = translator(interaction.locale);
const focusedOption = interaction.options.getFocused(true);
@@ -31,7 +31,7 @@ export async function autocompleteTanks(
go(
focusedOption.value,
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
{ keys: SEARCH_KEYS, limit: 10 }
{ keys: SEARCH_KEYS, limit: 10 },
).map(async (item) => {
let name = unwrap(item.obj.searchableName);
@@ -42,7 +42,7 @@ export async function autocompleteTanks(
0,
unwrap(item.obj.searchableName).length -
overSize -
OVERFLOW_SUFFIX.length
OVERFLOW_SUFFIX.length,
)}${OVERFLOW_SUFFIX}`;
}
@@ -50,8 +50,8 @@ export async function autocompleteTanks(
name,
value: `${item.obj.id}`,
} satisfies ApplicationCommandOptionChoiceData<string>;
})
}),
)
: []
: [],
);
}
+6 -6
View File
@@ -5,13 +5,13 @@ import {
tankDefinitions,
} from "./core/blitzkit/nonBlockingPromises";
let manager: ShardingManager;
let iteration = 0;
const interval = setInterval(async () => {
iteration++;
console.log(`Attempting launch on iteration ${++iteration}`);
console.log(`Attempting launch on iteration ${iteration}`);
const manager = new ShardingManager("dist/bot/workers/bot.js", {
manager?.respawnAll();
manager = new ShardingManager("dist/bot/workers/bot.js", {
token: assertSecret(import.meta.env.DISCORD_TOKEN),
});
@@ -21,7 +21,7 @@ const interval = setInterval(async () => {
console.log(`🟡 Launching shard ${shard.id}`);
shard.on("ready", () => console.log(`🟢 Launched shard ${shard.id}`));
})
.spawn();
.spawn({ timeout: 60000 });
try {
let servers = 0;
@@ -78,4 +78,4 @@ const interval = setInterval(async () => {
error,
);
}
}, 5000);
}, 15000);
-1
View File
@@ -19,7 +19,6 @@
"dotenv": "^17.2.2",
"fast-xml-parser": "^5.3.2",
"lodash-es": "^4.17.21",
"lz4js": "^0.2.0",
"pickleparser": "^0.2.1",
"protobufjs": "^7.5.4",
"three": "^0.180.0",
+4 -2
View File
@@ -1,5 +1,7 @@
import { ShellDefinition, ShellType } from "../protos";
export function canSplash(type: ShellDefinition["type"]): type is ShellType.HE {
return type === ShellType.HE;
export function canSplash(
type: ShellDefinition["type"],
): type is ShellType.SHELL_TYPE_HE {
return type === ShellType.SHELL_TYPE_HE;
}
+10 -10
View File
@@ -2,22 +2,22 @@ import { TankClass, TankType } from "../protos";
import type { BlitzStats } from "../statistics";
export const TANK_TYPES = [
TankType.RESEARCHABLE,
TankType.PREMIUM,
TankType.COLLECTOR,
TankType.TANK_TYPE_RESEARCHABLE,
TankType.TANK_TYPE_PREMIUM,
TankType.TANK_TYPE_COLLECTOR,
];
export const TANK_TYPE_COMMAND_NAMES = {
[TankType.RESEARCHABLE]: "researchable",
[TankType.PREMIUM]: "premium",
[TankType.COLLECTOR]: "collector",
[TankType.TANK_TYPE_RESEARCHABLE]: "researchable",
[TankType.TANK_TYPE_PREMIUM]: "premium",
[TankType.TANK_TYPE_COLLECTOR]: "collector",
};
export const TANK_CLASSES = [
TankClass.LIGHT,
TankClass.MEDIUM,
TankClass.HEAVY,
TankClass.TANK_DESTROYER,
TankClass.TANK_CLASS_LIGHT,
TankClass.TANK_CLASS_MEDIUM,
TankClass.TANK_CLASS_HEAVY,
TankClass.TANK_CLASS_TANK_DESTROYER,
];
export const emptyAllStats: BlitzStats = {
@@ -9,7 +9,7 @@ import {
export function checkConsumableProvisionInclusivity(
consumableProvision: Consumable | Provision,
tank: TankDefinition,
gun: GunDefinition
gun: GunDefinition,
) {
const included = consumableProvision.include?.every((rule) => {
switch (rule.filter_type!.$case) {
@@ -46,7 +46,7 @@ export function checkConsumableProvisionInclusivity(
case "categories":
return rule.filter_type!.value.categories.some((category) => {
switch (category) {
case ConsumableTankCategoryFilterCategory.CLIP:
case ConsumableTankCategoryFilterCategory.CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP:
return gun.gun_type!.$case !== "regular";
}
});
+3 -3
View File
@@ -1,7 +1,7 @@
import { ShellDefinition, ShellType } from "../protos";
export function isExplosive(
type: ShellDefinition["type"]
): type is ShellType.HEAT | ShellType.HE {
return type === ShellType.HEAT || type === ShellType.HE;
type: ShellDefinition["type"],
): type is ShellType.SHELL_TYPE_HEAT | ShellType.SHELL_TYPE_HE {
return type === ShellType.SHELL_TYPE_HEAT || type === ShellType.SHELL_TYPE_HE;
}
+7 -7
View File
@@ -2,27 +2,27 @@ import { TANK_CLASSES } from "../blitz/constants";
import { GameDefinitions, TankDefinition, TankType } from "../protos";
const treeTypeOrder = [
TankType.RESEARCHABLE,
TankType.PREMIUM,
TankType.COLLECTOR,
TankType.TANK_TYPE_RESEARCHABLE,
TankType.TANK_TYPE_PREMIUM,
TankType.TANK_TYPE_COLLECTOR,
];
export function metaSortTank(
tanks: TankDefinition[],
gameDefinitions: GameDefinitions
gameDefinitions: GameDefinitions,
) {
return tanks
.sort((a, b) => b.tier - a.tier)
.sort(
(a, b) => treeTypeOrder.indexOf(b.type) - treeTypeOrder.indexOf(a.type)
(a, b) => treeTypeOrder.indexOf(b.type) - treeTypeOrder.indexOf(a.type),
)
.sort(
(a, b) => TANK_CLASSES.indexOf(b.class) - TANK_CLASSES.indexOf(a.class)
(a, b) => TANK_CLASSES.indexOf(b.class) - TANK_CLASSES.indexOf(a.class),
)
.sort(
(a, b) =>
gameDefinitions.nations.indexOf(b.nation) -
gameDefinitions.nations.indexOf(a.nation)
gameDefinitions.nations.indexOf(a.nation),
)
.sort((a, b) => a.tier - b.tier);
}
@@ -2,8 +2,8 @@ import { BoundingBox, Vector3 } from "../protos";
export function normalizeBoundingBox(boundingBox: BoundingBox) {
return {
x: boundingBox.max.x - boundingBox.min.x,
y: boundingBox.max.y - boundingBox.min.y,
z: boundingBox.max.z - boundingBox.min.z,
x: boundingBox.max!.x - boundingBox.min!.x,
y: boundingBox.max!.y - boundingBox.min!.y,
z: boundingBox.max!.z - boundingBox.min!.z,
} satisfies Vector3;
}
@@ -1,16 +1,21 @@
import { ShellType } from '../protos';
import { Equalizer, ShellType } from "../protos";
export function resolvePenetrationCoefficient(
calibratedShells: boolean,
equalize: boolean,
type: ShellType,
equalizerObj?: Equalizer,
) {
if (!calibratedShells) return 1;
const calibrated = calibratedShells
? type === ShellType.SHELL_TYPE_AP
? 1.08
: type === ShellType.SHELL_TYPE_APCR
? 1.05
: type === ShellType.SHELL_TYPE_HEAT
? 1.13
: 1.08
: 1;
const equalizer = (equalize ? equalizerObj?.penetration : undefined) ?? 1;
return type === ShellType.AP
? 1.08
: type === ShellType.APCR
? 1.05
: type === ShellType.HEAT
? 1.13
: 1.08;
return calibrated * equalizer;
}
@@ -1,74 +1,74 @@
import { times } from 'lodash-es';
import { CrewType, ShellType, TankClass, TankType } from '../../protos';
import { times } from "lodash-es";
import { CrewType, ShellType, TankClass, TankType } from "../../protos";
export const SHELL_NAMES: Record<ShellType, string> = {
[ShellType.AP]: 'AP',
[ShellType.APCR]: 'APCR',
[ShellType.HEAT]: 'HEAT',
[ShellType.HE]: 'HE',
[ShellType.SHELL_TYPE_AP]: "AP",
[ShellType.SHELL_TYPE_APCR]: "APCR",
[ShellType.SHELL_TYPE_HEAT]: "HEAT",
[ShellType.SHELL_TYPE_HE]: "HE",
};
export const CREW_MEMBER_NAMES = {
[CrewType.COMMANDER]: 'commander',
[CrewType.DRIVER]: 'driver',
[CrewType.GUNNER]: 'gunner',
[CrewType.LOADER]: 'loader',
[CrewType.RADIOMAN]: 'radioman',
[CrewType.CREW_TYPE_COMMANDER]: "commander",
[CrewType.CREW_TYPE_DRIVER]: "driver",
[CrewType.CREW_TYPE_GUNNER]: "gunner",
[CrewType.CREW_TYPE_LOADER]: "loader",
[CrewType.CREW_TYPE_RADIOMAN]: "radioman",
} as const;
/**
* @deprecated use svg
*/
export const TANK_ICONS: Record<TankClass, string> = {
[TankClass.TANK_DESTROYER]: 'https://i.imgur.com/BIHSEH0.png',
[TankClass.LIGHT]: 'https://i.imgur.com/CSNha5V.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/wvf3ltm.png',
[TankClass.HEAVY]: 'https://i.imgur.com/ECeqlZa.png',
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/BIHSEH0.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/CSNha5V.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/wvf3ltm.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/ECeqlZa.png",
};
/**
* @deprecated use svg
*/
export const TANK_ICONS_PREMIUM: Record<TankClass, string> = {
[TankClass.TANK_DESTROYER]: 'https://i.imgur.com/TCu3EdR.png',
[TankClass.LIGHT]: 'https://i.imgur.com/zdkpTRb.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/3z7eHX6.png',
[TankClass.HEAVY]: 'https://i.imgur.com/P3vbmyA.png',
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/TCu3EdR.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/zdkpTRb.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/3z7eHX6.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/P3vbmyA.png",
};
/**
* @deprecated use svg
*/
export const TANK_ICONS_COLLECTOR: Record<TankClass, string> = {
[TankClass.TANK_DESTROYER]: 'https://i.imgur.com/WTjeirB.png',
[TankClass.LIGHT]: 'https://i.imgur.com/EwhtKkU.png',
[TankClass.MEDIUM]: 'https://i.imgur.com/u8YDMBh.png',
[TankClass.HEAVY]: 'https://i.imgur.com/8xRf3nc.png',
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/WTjeirB.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/EwhtKkU.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/u8YDMBh.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/8xRf3nc.png",
};
export const TIERS = times(10, (index) => index + 1);
export const TIER_ROMAN_NUMERALS: Record<number, string> = {
1: 'I',
2: 'II',
3: 'III',
4: 'IV',
5: 'V',
6: 'VI',
7: 'VII',
8: 'VIII',
9: 'IX',
10: 'X',
1: "I",
2: "II",
3: "III",
4: "IV",
5: "V",
6: "VI",
7: "VII",
8: "VIII",
9: "IX",
10: "X",
};
export const flags: Record<string, string> = {
ussr: '<:ussr:1218421042033197197>',
germany: '🇩🇪',
usa: '🇺🇸',
china: '🇨🇳',
uk: '🇬🇧',
france: '🇫🇷',
japan: '🇯🇵',
european: '🇪🇺',
other: '<:other:1218421572243558482>',
ussr: "<:ussr:1218421042033197197>",
germany: "🇩🇪",
usa: "🇺🇸",
china: "🇨🇳",
uk: "🇬🇧",
france: "🇫🇷",
japan: "🇯🇵",
european: "🇪🇺",
other: "<:other:1218421572243558482>",
};
export const TREE_TYPE_ICONS: Record<TankType, Record<TankClass, string>> = {
[TankType.RESEARCHABLE]: TANK_ICONS,
[TankType.PREMIUM]: TANK_ICONS_PREMIUM,
[TankType.COLLECTOR]: TANK_ICONS_COLLECTOR,
[TankType.TANK_TYPE_RESEARCHABLE]: TANK_ICONS,
[TankType.TANK_TYPE_PREMIUM]: TANK_ICONS_PREMIUM,
[TankType.TANK_TYPE_COLLECTOR]: TANK_ICONS_COLLECTOR,
};
+4 -4
View File
@@ -15,7 +15,7 @@ export async function fetchTankNames() {
tankDefinitionsArray.map(async (tank) => {
const searchableNameDeburr: I18nString = { locales: {} };
Object.entries(tank.name).forEach(([key, value]) => {
Object.entries(tank.name!).forEach(([key, value]) => {
searchableNameDeburr.locales[key] = deburr(value);
});
@@ -28,8 +28,8 @@ export async function fetchTankNames() {
?.map((id) =>
locales.supported.map(
({ locale }) =>
camouflageDefinitions.camouflages[id]?.name.locales[locale]
)
camouflageDefinitions.camouflages[id]?.name!.locales[locale],
),
)
.flat()
.filter(Boolean)
@@ -37,7 +37,7 @@ export async function fetchTankNames() {
.join(" "),
treeType: tank.type,
};
})
}),
);
}
@@ -3,14 +3,14 @@ import { BoundingBox } from "../protos";
export function unionBoundingBox(a: BoundingBox, b: BoundingBox) {
return {
min: {
x: Math.min(a.min.x, b.min.x),
y: Math.min(a.min.y, b.min.y),
z: Math.min(a.min.z, b.min.z),
x: Math.min(a.min!.x, b.min!.x),
y: Math.min(a.min!.y, b.min!.y),
z: Math.min(a.min!.z, b.min!.z),
},
max: {
x: Math.max(a.max.x, b.max.x),
y: Math.max(a.max.y, b.max.y),
z: Math.max(a.max.z, b.max.z),
x: Math.max(a.max!.x, b.max!.x),
y: Math.max(a.max!.y, b.max!.y),
z: Math.max(a.max!.z, b.max!.z),
},
} satisfies BoundingBox;
}
@@ -4,44 +4,44 @@ package blitzkit;
message AverageDefinitions {
map<uint32, AverageDefinitionsEntry> averages = 1;
required Samples samples = 2;
required uint64 time = 3;
required Samples samples = 2;
required uint64 time = 3;
}
message AverageDefinitionsEntry {
required AverageDefinitionsAllStats mu = 1;
required AverageDefinitionsAllStats sigma = 2;
required AverageDefinitionsAllStats r = 3;
required Samples samples = 4;
required AverageDefinitionsAllStats mu = 1;
required AverageDefinitionsAllStats sigma = 2;
required AverageDefinitionsAllStats r = 3;
required Samples samples = 4;
}
message AverageDefinitionsAllStats {
required float battles = 1;
required float capture_points = 2;
required float damage_dealt = 3;
required float damage_received = 4;
required float battles = 1;
required float capture_points = 2;
required float damage_dealt = 3;
required float damage_received = 4;
required float dropped_capture_points = 5;
required float frags = 6;
required float frags8p = 7;
required float hits = 8;
required float losses = 9;
required float max_frags = 10;
required float max_xp = 11;
required float shots = 12;
required float spotted = 13;
required float survived_battles = 14;
required float win_and_survived = 15;
required float wins = 16;
required float xp = 17;
required float battle_life_time = 18;
required float frags = 6;
required float frags8p = 7;
required float hits = 8;
required float losses = 9;
required float max_frags = 10;
required float max_xp = 11;
required float shots = 12;
required float spotted = 13;
required float survived_battles = 14;
required float win_and_survived = 15;
required float wins = 16;
required float xp = 17;
required float battle_life_time = 18;
}
message Samples {
required uint32 d_1 = 1;
required uint32 d_7 = 2;
required uint32 d_30 = 3;
required uint32 d_60 = 4;
required uint32 d_90 = 5;
required uint32 d_1 = 1;
required uint32 d_7 = 2;
required uint32 d_30 = 3;
required uint32 d_60 = 4;
required uint32 d_90 = 5;
required uint32 d_120 = 6;
required uint32 total = 7;
}
+127 -107
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/average_definitions.proto
// source: average_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -11,7 +11,7 @@ export const protobufPackage = "blitzkit";
export interface AverageDefinitions {
averages: { [key: number]: AverageDefinitionsEntry };
samples: Samples;
samples: Samples | undefined;
time: number;
}
@@ -21,10 +21,10 @@ export interface AverageDefinitions_AveragesEntry {
}
export interface AverageDefinitionsEntry {
mu: AverageDefinitionsAllStats;
sigma: AverageDefinitionsAllStats;
r: AverageDefinitionsAllStats;
samples: Samples;
mu: AverageDefinitionsAllStats | undefined;
sigma: AverageDefinitionsAllStats | undefined;
r: AverageDefinitionsAllStats | undefined;
samples: Samples | undefined;
}
export interface AverageDefinitionsAllStats {
@@ -58,13 +58,13 @@ export interface Samples {
total: number;
}
export function createBaseAverageDefinitions(): AverageDefinitions {
return { averages: {}, samples: createBaseSamples(), time: 0 };
function createBaseAverageDefinitions(): AverageDefinitions {
return { averages: {}, samples: undefined, time: 0 };
}
export const AverageDefinitions: MessageFns<AverageDefinitions> = {
encode(message: AverageDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.averages).forEach(([key, value]) => {
globalThis.Object.entries(message.averages).forEach(([key, value]: [string, AverageDefinitionsEntry]) => {
AverageDefinitions_AveragesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
if (message.samples !== undefined) {
@@ -78,7 +78,7 @@ export const AverageDefinitions: MessageFns<AverageDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): AverageDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAverageDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -122,20 +122,23 @@ export const AverageDefinitions: MessageFns<AverageDefinitions> = {
fromJSON(object: any): AverageDefinitions {
return {
averages: isObject(object.averages)
? Object.entries(object.averages).reduce<{ [key: number]: AverageDefinitionsEntry }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = AverageDefinitionsEntry.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.averages) as [string, any][]).reduce(
(acc: { [key: number]: AverageDefinitionsEntry }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = AverageDefinitionsEntry.fromJSON(value);
return acc;
},
{},
)
: {},
samples: Samples.fromJSON(assertSet("AverageDefinitions.samples", object.samples)),
time: globalThis.Number(assertSet("AverageDefinitions.time", object.time)),
samples: isSet(object.samples) ? Samples.fromJSON(object.samples) : undefined,
time: isSet(object.time) ? globalThis.Number(object.time) : 0,
};
},
toJSON(message: AverageDefinitions): unknown {
const obj: any = {};
if (message.averages) {
const entries = Object.entries(message.averages);
const entries = globalThis.Object.entries(message.averages) as [string, AverageDefinitionsEntry][];
if (entries.length > 0) {
obj.averages = {};
entries.forEach(([k, v]) => {
@@ -157,8 +160,8 @@ export const AverageDefinitions: MessageFns<AverageDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<AverageDefinitions>, I>>(object: I): AverageDefinitions {
const message = createBaseAverageDefinitions();
message.averages = Object.entries(object.averages ?? {}).reduce<{ [key: number]: AverageDefinitionsEntry }>(
(acc, [key, value]) => {
message.averages = (globalThis.Object.entries(object.averages ?? {}) as [string, AverageDefinitionsEntry][]).reduce(
(acc: { [key: number]: AverageDefinitionsEntry }, [key, value]: [string, AverageDefinitionsEntry]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = AverageDefinitionsEntry.fromPartial(value);
}
@@ -168,19 +171,19 @@ export const AverageDefinitions: MessageFns<AverageDefinitions> = {
);
message.samples = (object.samples !== undefined && object.samples !== null)
? Samples.fromPartial(object.samples)
: createBaseSamples();
: undefined;
message.time = object.time ?? 0;
return message;
},
};
export function createBaseAverageDefinitions_AveragesEntry(): AverageDefinitions_AveragesEntry {
return { key: 0, value: createBaseAverageDefinitionsEntry() };
function createBaseAverageDefinitions_AveragesEntry(): AverageDefinitions_AveragesEntry {
return { key: 0, value: undefined };
}
export const AverageDefinitions_AveragesEntry: MessageFns<AverageDefinitions_AveragesEntry> = {
encode(message: AverageDefinitions_AveragesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -191,7 +194,7 @@ export const AverageDefinitions_AveragesEntry: MessageFns<AverageDefinitions_Ave
decode(input: BinaryReader | Uint8Array, length?: number): AverageDefinitions_AveragesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAverageDefinitions_AveragesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -223,14 +226,14 @@ export const AverageDefinitions_AveragesEntry: MessageFns<AverageDefinitions_Ave
fromJSON(object: any): AverageDefinitions_AveragesEntry {
return {
key: globalThis.Number(assertSet("AverageDefinitions_AveragesEntry.key", object.key)),
value: AverageDefinitionsEntry.fromJSON(assertSet("AverageDefinitions_AveragesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? AverageDefinitionsEntry.fromJSON(object.value) : undefined,
};
},
toJSON(message: AverageDefinitions_AveragesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -251,18 +254,13 @@ export const AverageDefinitions_AveragesEntry: MessageFns<AverageDefinitions_Ave
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? AverageDefinitionsEntry.fromPartial(object.value)
: createBaseAverageDefinitionsEntry();
: undefined;
return message;
},
};
export function createBaseAverageDefinitionsEntry(): AverageDefinitionsEntry {
return {
mu: createBaseAverageDefinitionsAllStats(),
sigma: createBaseAverageDefinitionsAllStats(),
r: createBaseAverageDefinitionsAllStats(),
samples: createBaseSamples(),
};
function createBaseAverageDefinitionsEntry(): AverageDefinitionsEntry {
return { mu: undefined, sigma: undefined, r: undefined, samples: undefined };
}
export const AverageDefinitionsEntry: MessageFns<AverageDefinitionsEntry> = {
@@ -284,7 +282,7 @@ export const AverageDefinitionsEntry: MessageFns<AverageDefinitionsEntry> = {
decode(input: BinaryReader | Uint8Array, length?: number): AverageDefinitionsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAverageDefinitionsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -332,10 +330,10 @@ export const AverageDefinitionsEntry: MessageFns<AverageDefinitionsEntry> = {
fromJSON(object: any): AverageDefinitionsEntry {
return {
mu: AverageDefinitionsAllStats.fromJSON(assertSet("AverageDefinitionsEntry.mu", object.mu)),
sigma: AverageDefinitionsAllStats.fromJSON(assertSet("AverageDefinitionsEntry.sigma", object.sigma)),
r: AverageDefinitionsAllStats.fromJSON(assertSet("AverageDefinitionsEntry.r", object.r)),
samples: Samples.fromJSON(assertSet("AverageDefinitionsEntry.samples", object.samples)),
mu: isSet(object.mu) ? AverageDefinitionsAllStats.fromJSON(object.mu) : undefined,
sigma: isSet(object.sigma) ? AverageDefinitionsAllStats.fromJSON(object.sigma) : undefined,
r: isSet(object.r) ? AverageDefinitionsAllStats.fromJSON(object.r) : undefined,
samples: isSet(object.samples) ? Samples.fromJSON(object.samples) : undefined,
};
},
@@ -363,21 +361,21 @@ export const AverageDefinitionsEntry: MessageFns<AverageDefinitionsEntry> = {
const message = createBaseAverageDefinitionsEntry();
message.mu = (object.mu !== undefined && object.mu !== null)
? AverageDefinitionsAllStats.fromPartial(object.mu)
: createBaseAverageDefinitionsAllStats();
: undefined;
message.sigma = (object.sigma !== undefined && object.sigma !== null)
? AverageDefinitionsAllStats.fromPartial(object.sigma)
: createBaseAverageDefinitionsAllStats();
: undefined;
message.r = (object.r !== undefined && object.r !== null)
? AverageDefinitionsAllStats.fromPartial(object.r)
: createBaseAverageDefinitionsAllStats();
: undefined;
message.samples = (object.samples !== undefined && object.samples !== null)
? Samples.fromPartial(object.samples)
: createBaseSamples();
: undefined;
return message;
},
};
export function createBaseAverageDefinitionsAllStats(): AverageDefinitionsAllStats {
function createBaseAverageDefinitionsAllStats(): AverageDefinitionsAllStats {
return {
battles: 0,
capture_points: 0,
@@ -461,7 +459,7 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
decode(input: BinaryReader | Uint8Array, length?: number): AverageDefinitionsAllStats {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAverageDefinitionsAllStats();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -621,34 +619,60 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
fromJSON(object: any): AverageDefinitionsAllStats {
return {
battles: globalThis.Number(assertSet("AverageDefinitionsAllStats.battles", object.battles)),
capture_points: globalThis.Number(assertSet("AverageDefinitionsAllStats.capture_points", object.capture_points)),
damage_dealt: globalThis.Number(assertSet("AverageDefinitionsAllStats.damage_dealt", object.damage_dealt)),
damage_received: globalThis.Number(
assertSet("AverageDefinitionsAllStats.damage_received", object.damage_received),
),
dropped_capture_points: globalThis.Number(
assertSet("AverageDefinitionsAllStats.dropped_capture_points", object.dropped_capture_points),
),
frags: globalThis.Number(assertSet("AverageDefinitionsAllStats.frags", object.frags)),
frags8p: globalThis.Number(assertSet("AverageDefinitionsAllStats.frags8p", object.frags8p)),
hits: globalThis.Number(assertSet("AverageDefinitionsAllStats.hits", object.hits)),
losses: globalThis.Number(assertSet("AverageDefinitionsAllStats.losses", object.losses)),
max_frags: globalThis.Number(assertSet("AverageDefinitionsAllStats.max_frags", object.max_frags)),
max_xp: globalThis.Number(assertSet("AverageDefinitionsAllStats.max_xp", object.max_xp)),
shots: globalThis.Number(assertSet("AverageDefinitionsAllStats.shots", object.shots)),
spotted: globalThis.Number(assertSet("AverageDefinitionsAllStats.spotted", object.spotted)),
survived_battles: globalThis.Number(
assertSet("AverageDefinitionsAllStats.survived_battles", object.survived_battles),
),
win_and_survived: globalThis.Number(
assertSet("AverageDefinitionsAllStats.win_and_survived", object.win_and_survived),
),
wins: globalThis.Number(assertSet("AverageDefinitionsAllStats.wins", object.wins)),
xp: globalThis.Number(assertSet("AverageDefinitionsAllStats.xp", object.xp)),
battle_life_time: globalThis.Number(
assertSet("AverageDefinitionsAllStats.battle_life_time", object.battle_life_time),
),
battles: isSet(object.battles) ? globalThis.Number(object.battles) : 0,
capture_points: isSet(object.capturePoints)
? globalThis.Number(object.capturePoints)
: isSet(object.capture_points)
? globalThis.Number(object.capture_points)
: 0,
damage_dealt: isSet(object.damageDealt)
? globalThis.Number(object.damageDealt)
: isSet(object.damage_dealt)
? globalThis.Number(object.damage_dealt)
: 0,
damage_received: isSet(object.damageReceived)
? globalThis.Number(object.damageReceived)
: isSet(object.damage_received)
? globalThis.Number(object.damage_received)
: 0,
dropped_capture_points: isSet(object.droppedCapturePoints)
? globalThis.Number(object.droppedCapturePoints)
: isSet(object.dropped_capture_points)
? globalThis.Number(object.dropped_capture_points)
: 0,
frags: isSet(object.frags) ? globalThis.Number(object.frags) : 0,
frags8p: isSet(object.frags8p) ? globalThis.Number(object.frags8p) : 0,
hits: isSet(object.hits) ? globalThis.Number(object.hits) : 0,
losses: isSet(object.losses) ? globalThis.Number(object.losses) : 0,
max_frags: isSet(object.maxFrags)
? globalThis.Number(object.maxFrags)
: isSet(object.max_frags)
? globalThis.Number(object.max_frags)
: 0,
max_xp: isSet(object.maxXp)
? globalThis.Number(object.maxXp)
: isSet(object.max_xp)
? globalThis.Number(object.max_xp)
: 0,
shots: isSet(object.shots) ? globalThis.Number(object.shots) : 0,
spotted: isSet(object.spotted) ? globalThis.Number(object.spotted) : 0,
survived_battles: isSet(object.survivedBattles)
? globalThis.Number(object.survivedBattles)
: isSet(object.survived_battles)
? globalThis.Number(object.survived_battles)
: 0,
win_and_survived: isSet(object.winAndSurvived)
? globalThis.Number(object.winAndSurvived)
: isSet(object.win_and_survived)
? globalThis.Number(object.win_and_survived)
: 0,
wins: isSet(object.wins) ? globalThis.Number(object.wins) : 0,
xp: isSet(object.xp) ? globalThis.Number(object.xp) : 0,
battle_life_time: isSet(object.battleLifeTime)
? globalThis.Number(object.battleLifeTime)
: isSet(object.battle_life_time)
? globalThis.Number(object.battle_life_time)
: 0,
};
},
@@ -658,16 +682,16 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
obj.battles = message.battles;
}
if (message.capture_points !== 0) {
obj.capture_points = message.capture_points;
obj.capturePoints = message.capture_points;
}
if (message.damage_dealt !== 0) {
obj.damage_dealt = message.damage_dealt;
obj.damageDealt = message.damage_dealt;
}
if (message.damage_received !== 0) {
obj.damage_received = message.damage_received;
obj.damageReceived = message.damage_received;
}
if (message.dropped_capture_points !== 0) {
obj.dropped_capture_points = message.dropped_capture_points;
obj.droppedCapturePoints = message.dropped_capture_points;
}
if (message.frags !== 0) {
obj.frags = message.frags;
@@ -682,10 +706,10 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
obj.losses = message.losses;
}
if (message.max_frags !== 0) {
obj.max_frags = message.max_frags;
obj.maxFrags = message.max_frags;
}
if (message.max_xp !== 0) {
obj.max_xp = message.max_xp;
obj.maxXp = message.max_xp;
}
if (message.shots !== 0) {
obj.shots = message.shots;
@@ -694,10 +718,10 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
obj.spotted = message.spotted;
}
if (message.survived_battles !== 0) {
obj.survived_battles = message.survived_battles;
obj.survivedBattles = message.survived_battles;
}
if (message.win_and_survived !== 0) {
obj.win_and_survived = message.win_and_survived;
obj.winAndSurvived = message.win_and_survived;
}
if (message.wins !== 0) {
obj.wins = message.wins;
@@ -706,7 +730,7 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
obj.xp = message.xp;
}
if (message.battle_life_time !== 0) {
obj.battle_life_time = message.battle_life_time;
obj.battleLifeTime = message.battle_life_time;
}
return obj;
},
@@ -738,7 +762,7 @@ export const AverageDefinitionsAllStats: MessageFns<AverageDefinitionsAllStats>
},
};
export function createBaseSamples(): Samples {
function createBaseSamples(): Samples {
return { d_1: 0, d_7: 0, d_30: 0, d_60: 0, d_90: 0, d_120: 0, total: 0 };
}
@@ -770,7 +794,7 @@ export const Samples: MessageFns<Samples> = {
decode(input: BinaryReader | Uint8Array, length?: number): Samples {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseSamples();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -842,35 +866,39 @@ export const Samples: MessageFns<Samples> = {
fromJSON(object: any): Samples {
return {
d_1: globalThis.Number(assertSet("Samples.d_1", object.d_1)),
d_7: globalThis.Number(assertSet("Samples.d_7", object.d_7)),
d_30: globalThis.Number(assertSet("Samples.d_30", object.d_30)),
d_60: globalThis.Number(assertSet("Samples.d_60", object.d_60)),
d_90: globalThis.Number(assertSet("Samples.d_90", object.d_90)),
d_120: globalThis.Number(assertSet("Samples.d_120", object.d_120)),
total: globalThis.Number(assertSet("Samples.total", object.total)),
d_1: isSet(object.d1) ? globalThis.Number(object.d1) : isSet(object.d_1) ? globalThis.Number(object.d_1) : 0,
d_7: isSet(object.d7) ? globalThis.Number(object.d7) : isSet(object.d_7) ? globalThis.Number(object.d_7) : 0,
d_30: isSet(object.d30) ? globalThis.Number(object.d30) : isSet(object.d_30) ? globalThis.Number(object.d_30) : 0,
d_60: isSet(object.d60) ? globalThis.Number(object.d60) : isSet(object.d_60) ? globalThis.Number(object.d_60) : 0,
d_90: isSet(object.d90) ? globalThis.Number(object.d90) : isSet(object.d_90) ? globalThis.Number(object.d_90) : 0,
d_120: isSet(object.d120)
? globalThis.Number(object.d120)
: isSet(object.d_120)
? globalThis.Number(object.d_120)
: 0,
total: isSet(object.total) ? globalThis.Number(object.total) : 0,
};
},
toJSON(message: Samples): unknown {
const obj: any = {};
if (message.d_1 !== 0) {
obj.d_1 = Math.round(message.d_1);
obj.d1 = Math.round(message.d_1);
}
if (message.d_7 !== 0) {
obj.d_7 = Math.round(message.d_7);
obj.d7 = Math.round(message.d_7);
}
if (message.d_30 !== 0) {
obj.d_30 = Math.round(message.d_30);
obj.d30 = Math.round(message.d_30);
}
if (message.d_60 !== 0) {
obj.d_60 = Math.round(message.d_60);
obj.d60 = Math.round(message.d_60);
}
if (message.d_90 !== 0) {
obj.d_90 = Math.round(message.d_90);
obj.d90 = Math.round(message.d_90);
}
if (message.d_120 !== 0) {
obj.d_120 = Math.round(message.d_120);
obj.d120 = Math.round(message.d_120);
}
if (message.total !== 0) {
obj.total = Math.round(message.total);
@@ -926,14 +954,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -2,15 +2,15 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message CamouflageDefinitions {
map<uint32, Camouflage> camouflages = 1;
}
message Camouflage {
required uint32 id = 1;
required I18nString name = 2;
optional I18nString tank_name = 3;
required uint32 id = 1;
required I18nString name = 2;
optional I18nString tank_name = 3;
optional I18nString tank_name_full = 4;
}
+140 -209
View File
@@ -1,14 +1,14 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/camouflage_definitions.proto
// source: camouflage_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
import { createBaseI18nString, I18nString } from './i18n';
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { I18nString } from "./i18n";
export const protobufPackage = 'blitzkit';
export const protobufPackage = "blitzkit";
export interface CamouflageDefinitions {
camouflages: { [key: number]: Camouflage };
@@ -21,36 +21,26 @@ export interface CamouflageDefinitions_CamouflagesEntry {
export interface Camouflage {
id: number;
name: I18nString;
tank_name?: I18nString;
tank_name_full?: I18nString;
name: I18nString | undefined;
tank_name?: I18nString | undefined;
tank_name_full?: I18nString | undefined;
}
export function createBaseCamouflageDefinitions(): CamouflageDefinitions {
function createBaseCamouflageDefinitions(): CamouflageDefinitions {
return { camouflages: {} };
}
export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
encode(
message: CamouflageDefinitions,
writer: BinaryWriter = new BinaryWriter(),
): BinaryWriter {
Object.entries(message.camouflages).forEach(([key, value]) => {
CamouflageDefinitions_CamouflagesEntry.encode(
{ key: key as any, value },
writer.uint32(10).fork(),
).join();
encode(message: CamouflageDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
globalThis.Object.entries(message.camouflages).forEach(([key, value]: [string, Camouflage]) => {
CamouflageDefinitions_CamouflagesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
},
decode(
input: BinaryReader | Uint8Array,
length?: number,
): CamouflageDefinitions {
const reader =
input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
decode(input: BinaryReader | Uint8Array, length?: number): CamouflageDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseCamouflageDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -60,10 +50,7 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
break;
}
const entry1 = CamouflageDefinitions_CamouflagesEntry.decode(
reader,
reader.uint32(),
);
const entry1 = CamouflageDefinitions_CamouflagesEntry.decode(reader, reader.uint32());
if (entry1.value !== undefined) {
message.camouflages[entry1.key] = entry1.value;
}
@@ -81,12 +68,13 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
fromJSON(object: any): CamouflageDefinitions {
return {
camouflages: isObject(object.camouflages)
? Object.entries(object.camouflages).reduce<{
[key: number]: Camouflage;
}>((acc, [key, value]) => {
? (globalThis.Object.entries(object.camouflages) as [string, any][]).reduce(
(acc: { [key: number]: Camouflage }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Camouflage.fromJSON(value);
return acc;
}, {})
},
{},
)
: {},
};
},
@@ -94,7 +82,7 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
toJSON(message: CamouflageDefinitions): unknown {
const obj: any = {};
if (message.camouflages) {
const entries = Object.entries(message.camouflages);
const entries = globalThis.Object.entries(message.camouflages) as [string, Camouflage][];
if (entries.length > 0) {
obj.camouflages = {};
entries.forEach(([k, v]) => {
@@ -105,141 +93,112 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
return obj;
},
create<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(
base?: I,
): CamouflageDefinitions {
create<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(base?: I): CamouflageDefinitions {
return CamouflageDefinitions.fromPartial(base ?? ({} as any));
},
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(
object: I,
): CamouflageDefinitions {
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(object: I): CamouflageDefinitions {
const message = createBaseCamouflageDefinitions();
message.camouflages = Object.entries(object.camouflages ?? {}).reduce<{
[key: number]: Camouflage;
}>((acc, [key, value]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Camouflage.fromPartial(value);
}
return acc;
}, {});
message.camouflages = (globalThis.Object.entries(object.camouflages ?? {}) as [string, Camouflage][]).reduce(
(acc: { [key: number]: Camouflage }, [key, value]: [string, Camouflage]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Camouflage.fromPartial(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseCamouflageDefinitions_CamouflagesEntry(): CamouflageDefinitions_CamouflagesEntry {
return { key: 0, value: createBaseCamouflage() };
function createBaseCamouflageDefinitions_CamouflagesEntry(): CamouflageDefinitions_CamouflagesEntry {
return { key: 0, value: undefined };
}
export const CamouflageDefinitions_CamouflagesEntry: MessageFns<CamouflageDefinitions_CamouflagesEntry> =
{
encode(
message: CamouflageDefinitions_CamouflagesEntry,
writer: BinaryWriter = new BinaryWriter(),
): BinaryWriter {
if (message.key !== undefined) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
Camouflage.encode(message.value, writer.uint32(18).fork()).join();
}
return writer;
},
export const CamouflageDefinitions_CamouflagesEntry: MessageFns<CamouflageDefinitions_CamouflagesEntry> = {
encode(message: CamouflageDefinitions_CamouflagesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
Camouflage.encode(message.value, writer.uint32(18).fork()).join();
}
return writer;
},
decode(
input: BinaryReader | Uint8Array,
length?: number,
): CamouflageDefinitions_CamouflagesEntry {
const reader =
input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
if (tag !== 8) {
break;
}
message.key = reader.uint32();
continue;
decode(input: BinaryReader | Uint8Array, length?: number): CamouflageDefinitions_CamouflagesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
if (tag !== 8) {
break;
}
case 2: {
if (tag !== 18) {
break;
}
message.value = Camouflage.decode(reader, reader.uint32());
continue;
message.key = reader.uint32();
continue;
}
case 2: {
if (tag !== 18) {
break;
}
message.value = Camouflage.decode(reader, reader.uint32());
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skip(tag & 7);
}
return message;
},
fromJSON(object: any): CamouflageDefinitions_CamouflagesEntry {
return {
key: globalThis.Number(
assertSet('CamouflageDefinitions_CamouflagesEntry.key', object.key),
),
value: Camouflage.fromJSON(
assertSet(
'CamouflageDefinitions_CamouflagesEntry.value',
object.value,
),
),
};
},
toJSON(message: CamouflageDefinitions_CamouflagesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
obj.key = Math.round(message.key);
if ((tag & 7) === 4 || tag === 0) {
break;
}
if (message.value !== undefined) {
obj.value = Camouflage.toJSON(message.value);
}
return obj;
},
reader.skip(tag & 7);
}
return message;
},
create<
I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>,
>(base?: I): CamouflageDefinitions_CamouflagesEntry {
return CamouflageDefinitions_CamouflagesEntry.fromPartial(
base ?? ({} as any),
);
},
fromPartial<
I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>,
>(object: I): CamouflageDefinitions_CamouflagesEntry {
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
message.key = object.key ?? 0;
message.value =
object.value !== undefined && object.value !== null
? Camouflage.fromPartial(object.value)
: createBaseCamouflage();
return message;
},
};
fromJSON(object: any): CamouflageDefinitions_CamouflagesEntry {
return {
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Camouflage.fromJSON(object.value) : undefined,
};
},
export function createBaseCamouflage(): Camouflage {
return {
id: 0,
name: createBaseI18nString(),
tank_name: undefined,
tank_name_full: undefined,
};
toJSON(message: CamouflageDefinitions_CamouflagesEntry): unknown {
const obj: any = {};
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
obj.value = Camouflage.toJSON(message.value);
}
return obj;
},
create<I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>>(
base?: I,
): CamouflageDefinitions_CamouflagesEntry {
return CamouflageDefinitions_CamouflagesEntry.fromPartial(base ?? ({} as any));
},
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>>(
object: I,
): CamouflageDefinitions_CamouflagesEntry {
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Camouflage.fromPartial(object.value)
: undefined;
return message;
},
};
function createBaseCamouflage(): Camouflage {
return { id: 0, name: undefined, tank_name: undefined, tank_name_full: undefined };
}
export const Camouflage: MessageFns<Camouflage> = {
encode(
message: Camouflage,
writer: BinaryWriter = new BinaryWriter(),
): BinaryWriter {
encode(message: Camouflage, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.id !== 0) {
writer.uint32(8).uint32(message.id);
}
@@ -250,18 +209,14 @@ export const Camouflage: MessageFns<Camouflage> = {
I18nString.encode(message.tank_name, writer.uint32(26).fork()).join();
}
if (message.tank_name_full !== undefined) {
I18nString.encode(
message.tank_name_full,
writer.uint32(34).fork(),
).join();
I18nString.encode(message.tank_name_full, writer.uint32(34).fork()).join();
}
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): Camouflage {
const reader =
input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseCamouflage();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -309,12 +264,16 @@ export const Camouflage: MessageFns<Camouflage> = {
fromJSON(object: any): Camouflage {
return {
id: globalThis.Number(assertSet('Camouflage.id', object.id)),
name: I18nString.fromJSON(assertSet('Camouflage.name', object.name)),
tank_name: isSet(object.tank_name)
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
tank_name: isSet(object.tankName)
? I18nString.fromJSON(object.tankName)
: isSet(object.tank_name)
? I18nString.fromJSON(object.tank_name)
: undefined,
tank_name_full: isSet(object.tank_name_full)
tank_name_full: isSet(object.tankNameFull)
? I18nString.fromJSON(object.tankNameFull)
: isSet(object.tank_name_full)
? I18nString.fromJSON(object.tank_name_full)
: undefined,
};
@@ -329,10 +288,10 @@ export const Camouflage: MessageFns<Camouflage> = {
obj.name = I18nString.toJSON(message.name);
}
if (message.tank_name !== undefined) {
obj.tank_name = I18nString.toJSON(message.tank_name);
obj.tankName = I18nString.toJSON(message.tank_name);
}
if (message.tank_name_full !== undefined) {
obj.tank_name_full = I18nString.toJSON(message.tank_name_full);
obj.tankNameFull = I18nString.toJSON(message.tank_name_full);
}
return obj;
},
@@ -340,71 +299,43 @@ export const Camouflage: MessageFns<Camouflage> = {
create<I extends Exact<DeepPartial<Camouflage>, I>>(base?: I): Camouflage {
return Camouflage.fromPartial(base ?? ({} as any));
},
fromPartial<I extends Exact<DeepPartial<Camouflage>, I>>(
object: I,
): Camouflage {
fromPartial<I extends Exact<DeepPartial<Camouflage>, I>>(object: I): Camouflage {
const message = createBaseCamouflage();
message.id = object.id ?? 0;
message.name =
object.name !== undefined && object.name !== null
? I18nString.fromPartial(object.name)
: createBaseI18nString();
message.tank_name =
object.tank_name !== undefined && object.tank_name !== null
? I18nString.fromPartial(object.tank_name)
: undefined;
message.tank_name_full =
object.tank_name_full !== undefined && object.tank_name_full !== null
? I18nString.fromPartial(object.tank_name_full)
: undefined;
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: undefined;
message.tank_name = (object.tank_name !== undefined && object.tank_name !== null)
? I18nString.fromPartial(object.tank_name)
: undefined;
message.tank_name_full = (object.tank_name_full !== undefined && object.tank_name_full !== null)
? I18nString.fromPartial(object.tank_name_full)
: undefined;
return message;
},
};
type Builtin =
| Date
| Function
| Uint8Array
| string
| number
| boolean
| undefined;
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin
? T
: T extends globalThis.Array<infer U>
? globalThis.Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T extends { $case: string; value: unknown }
? { $case: T['$case']; value?: DeepPartial<T['value']> }
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
export type DeepPartial<T> = T extends Builtin ? T
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends { $case: string; value: unknown } ? { $case: T["$case"]; value?: DeepPartial<T["value"]> }
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin
? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
};
export type Exact<P, I extends P> = P extends Builtin ? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
function isObject(value: any): boolean {
return typeof value === 'object' && value !== null;
return typeof value === "object" && value !== null;
}
function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -2,28 +2,28 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message ConsumableDefinitions {
map<uint32, Consumable> consumables = 1;
}
message Consumable {
required uint32 id = 1;
required I18nString name = 2;
required uint32 cooldown = 3;
optional float duration = 4;
required bool game_mode_exclusive = 5;
repeated ConsumableTankFilter include = 6;
repeated ConsumableTankFilter exclude = 7;
required uint32 id = 1;
required I18nString name = 2;
required uint32 cooldown = 3;
optional float duration = 4;
required bool game_mode_exclusive = 5;
repeated ConsumableTankFilter include = 6;
repeated ConsumableTankFilter exclude = 7;
}
message ConsumableTankFilter {
oneof filter_type {
ConsumableTankTierFilter tiers = 1;
ConsumableTankIdsFilter ids = 2;
ConsumableTankTierFilter tiers = 1;
ConsumableTankIdsFilter ids = 2;
ConsumableTankCategoryFilter categories = 3;
ConsumableTankNationFilter nations = 4;
ConsumableTankNationFilter nations = 4;
}
}
@@ -1,24 +1,24 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/consumable_definitions.proto
// source: consumable_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
export enum ConsumableTankCategoryFilterCategory {
CLIP = 0,
CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP = 0,
}
export function consumableTankCategoryFilterCategoryFromJSON(object: any): ConsumableTankCategoryFilterCategory {
switch (object) {
case 0:
case "CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP":
return ConsumableTankCategoryFilterCategory.CLIP;
return ConsumableTankCategoryFilterCategory.CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP;
default:
throw new globalThis.Error(
"Unrecognized enum value " + object + " for enum ConsumableTankCategoryFilterCategory",
@@ -28,7 +28,7 @@ export function consumableTankCategoryFilterCategoryFromJSON(object: any): Consu
export function consumableTankCategoryFilterCategoryToJSON(object: ConsumableTankCategoryFilterCategory): string {
switch (object) {
case ConsumableTankCategoryFilterCategory.CLIP:
case ConsumableTankCategoryFilterCategory.CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP:
return "CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP";
default:
throw new globalThis.Error(
@@ -48,7 +48,7 @@ export interface ConsumableDefinitions_ConsumablesEntry {
export interface Consumable {
id: number;
name: I18nString;
name: I18nString | undefined;
cooldown: number;
duration?: number | undefined;
game_mode_exclusive: boolean;
@@ -82,13 +82,13 @@ export interface ConsumableTankNationFilter {
nations: string[];
}
export function createBaseConsumableDefinitions(): ConsumableDefinitions {
function createBaseConsumableDefinitions(): ConsumableDefinitions {
return { consumables: {} };
}
export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
encode(message: ConsumableDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.consumables).forEach(([key, value]) => {
globalThis.Object.entries(message.consumables).forEach(([key, value]: [string, Consumable]) => {
ConsumableDefinitions_ConsumablesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -96,7 +96,7 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -124,10 +124,13 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
fromJSON(object: any): ConsumableDefinitions {
return {
consumables: isObject(object.consumables)
? Object.entries(object.consumables).reduce<{ [key: number]: Consumable }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = Consumable.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.consumables) as [string, any][]).reduce(
(acc: { [key: number]: Consumable }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Consumable.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -135,7 +138,7 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
toJSON(message: ConsumableDefinitions): unknown {
const obj: any = {};
if (message.consumables) {
const entries = Object.entries(message.consumables);
const entries = globalThis.Object.entries(message.consumables) as [string, Consumable][];
if (entries.length > 0) {
obj.consumables = {};
entries.forEach(([k, v]) => {
@@ -151,8 +154,8 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<ConsumableDefinitions>, I>>(object: I): ConsumableDefinitions {
const message = createBaseConsumableDefinitions();
message.consumables = Object.entries(object.consumables ?? {}).reduce<{ [key: number]: Consumable }>(
(acc, [key, value]) => {
message.consumables = (globalThis.Object.entries(object.consumables ?? {}) as [string, Consumable][]).reduce(
(acc: { [key: number]: Consumable }, [key, value]: [string, Consumable]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Consumable.fromPartial(value);
}
@@ -164,13 +167,13 @@ export const ConsumableDefinitions: MessageFns<ConsumableDefinitions> = {
},
};
export function createBaseConsumableDefinitions_ConsumablesEntry(): ConsumableDefinitions_ConsumablesEntry {
return { key: 0, value: createBaseConsumable() };
function createBaseConsumableDefinitions_ConsumablesEntry(): ConsumableDefinitions_ConsumablesEntry {
return { key: 0, value: undefined };
}
export const ConsumableDefinitions_ConsumablesEntry: MessageFns<ConsumableDefinitions_ConsumablesEntry> = {
encode(message: ConsumableDefinitions_ConsumablesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -181,7 +184,7 @@ export const ConsumableDefinitions_ConsumablesEntry: MessageFns<ConsumableDefini
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableDefinitions_ConsumablesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableDefinitions_ConsumablesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -213,14 +216,14 @@ export const ConsumableDefinitions_ConsumablesEntry: MessageFns<ConsumableDefini
fromJSON(object: any): ConsumableDefinitions_ConsumablesEntry {
return {
key: globalThis.Number(assertSet("ConsumableDefinitions_ConsumablesEntry.key", object.key)),
value: Consumable.fromJSON(assertSet("ConsumableDefinitions_ConsumablesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Consumable.fromJSON(object.value) : undefined,
};
},
toJSON(message: ConsumableDefinitions_ConsumablesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -241,21 +244,13 @@ export const ConsumableDefinitions_ConsumablesEntry: MessageFns<ConsumableDefini
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Consumable.fromPartial(object.value)
: createBaseConsumable();
: undefined;
return message;
},
};
export function createBaseConsumable(): Consumable {
return {
id: 0,
name: createBaseI18nString(),
cooldown: 0,
duration: undefined,
game_mode_exclusive: false,
include: [],
exclude: [],
};
function createBaseConsumable(): Consumable {
return { id: 0, name: undefined, cooldown: 0, duration: 0, game_mode_exclusive: false, include: [], exclude: [] };
}
export const Consumable: MessageFns<Consumable> = {
@@ -269,7 +264,7 @@ export const Consumable: MessageFns<Consumable> = {
if (message.cooldown !== 0) {
writer.uint32(24).uint32(message.cooldown);
}
if (message.duration !== undefined && message.duration !== undefined) {
if (message.duration !== undefined && message.duration !== 0) {
writer.uint32(37).float(message.duration);
}
if (message.game_mode_exclusive !== false) {
@@ -286,7 +281,7 @@ export const Consumable: MessageFns<Consumable> = {
decode(input: BinaryReader | Uint8Array, length?: number): Consumable {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumable();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -358,11 +353,15 @@ export const Consumable: MessageFns<Consumable> = {
fromJSON(object: any): Consumable {
return {
id: globalThis.Number(assertSet("Consumable.id", object.id)),
name: I18nString.fromJSON(assertSet("Consumable.name", object.name)),
cooldown: globalThis.Number(assertSet("Consumable.cooldown", object.cooldown)),
duration: isSet(object.duration) ? globalThis.Number(object.duration) : undefined,
game_mode_exclusive: globalThis.Boolean(assertSet("Consumable.game_mode_exclusive", object.game_mode_exclusive)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
cooldown: isSet(object.cooldown) ? globalThis.Number(object.cooldown) : 0,
duration: isSet(object.duration) ? globalThis.Number(object.duration) : 0,
game_mode_exclusive: isSet(object.gameModeExclusive)
? globalThis.Boolean(object.gameModeExclusive)
: isSet(object.game_mode_exclusive)
? globalThis.Boolean(object.game_mode_exclusive)
: false,
include: globalThis.Array.isArray(object?.include)
? object.include.map((e: any) => ConsumableTankFilter.fromJSON(e))
: [],
@@ -383,11 +382,11 @@ export const Consumable: MessageFns<Consumable> = {
if (message.cooldown !== 0) {
obj.cooldown = Math.round(message.cooldown);
}
if (message.duration !== undefined && message.duration !== undefined) {
if (message.duration !== undefined && message.duration !== 0) {
obj.duration = message.duration;
}
if (message.game_mode_exclusive !== false) {
obj.game_mode_exclusive = message.game_mode_exclusive;
obj.gameModeExclusive = message.game_mode_exclusive;
}
if (message.include?.length) {
obj.include = message.include.map((e) => ConsumableTankFilter.toJSON(e));
@@ -406,9 +405,9 @@ export const Consumable: MessageFns<Consumable> = {
message.id = object.id ?? 0;
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
: undefined;
message.cooldown = object.cooldown ?? 0;
message.duration = object.duration ?? undefined;
message.duration = object.duration ?? 0;
message.game_mode_exclusive = object.game_mode_exclusive ?? false;
message.include = object.include?.map((e) => ConsumableTankFilter.fromPartial(e)) || [];
message.exclude = object.exclude?.map((e) => ConsumableTankFilter.fromPartial(e)) || [];
@@ -416,7 +415,7 @@ export const Consumable: MessageFns<Consumable> = {
},
};
export function createBaseConsumableTankFilter(): ConsumableTankFilter {
function createBaseConsumableTankFilter(): ConsumableTankFilter {
return { filter_type: undefined };
}
@@ -441,7 +440,7 @@ export const ConsumableTankFilter: MessageFns<ConsumableTankFilter> = {
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableTankFilter {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableTankFilter();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -508,14 +507,11 @@ export const ConsumableTankFilter: MessageFns<ConsumableTankFilter> = {
const obj: any = {};
if (message.filter_type?.$case === "tiers") {
obj.tiers = ConsumableTankTierFilter.toJSON(message.filter_type.value);
}
if (message.filter_type?.$case === "ids") {
} else if (message.filter_type?.$case === "ids") {
obj.ids = ConsumableTankIdsFilter.toJSON(message.filter_type.value);
}
if (message.filter_type?.$case === "categories") {
} else if (message.filter_type?.$case === "categories") {
obj.categories = ConsumableTankCategoryFilter.toJSON(message.filter_type.value);
}
if (message.filter_type?.$case === "nations") {
} else if (message.filter_type?.$case === "nations") {
obj.nations = ConsumableTankNationFilter.toJSON(message.filter_type.value);
}
return obj;
@@ -526,45 +522,46 @@ export const ConsumableTankFilter: MessageFns<ConsumableTankFilter> = {
},
fromPartial<I extends Exact<DeepPartial<ConsumableTankFilter>, I>>(object: I): ConsumableTankFilter {
const message = createBaseConsumableTankFilter();
if (
object.filter_type?.$case === "tiers" &&
object.filter_type?.value !== undefined &&
object.filter_type?.value !== null
) {
message.filter_type = { $case: "tiers", value: ConsumableTankTierFilter.fromPartial(object.filter_type.value) };
}
if (
object.filter_type?.$case === "ids" &&
object.filter_type?.value !== undefined &&
object.filter_type?.value !== null
) {
message.filter_type = { $case: "ids", value: ConsumableTankIdsFilter.fromPartial(object.filter_type.value) };
}
if (
object.filter_type?.$case === "categories" &&
object.filter_type?.value !== undefined &&
object.filter_type?.value !== null
) {
message.filter_type = {
$case: "categories",
value: ConsumableTankCategoryFilter.fromPartial(object.filter_type.value),
};
}
if (
object.filter_type?.$case === "nations" &&
object.filter_type?.value !== undefined &&
object.filter_type?.value !== null
) {
message.filter_type = {
$case: "nations",
value: ConsumableTankNationFilter.fromPartial(object.filter_type.value),
};
switch (object.filter_type?.$case) {
case "tiers": {
if (object.filter_type?.value !== undefined && object.filter_type?.value !== null) {
message.filter_type = {
$case: "tiers",
value: ConsumableTankTierFilter.fromPartial(object.filter_type.value),
};
}
break;
}
case "ids": {
if (object.filter_type?.value !== undefined && object.filter_type?.value !== null) {
message.filter_type = { $case: "ids", value: ConsumableTankIdsFilter.fromPartial(object.filter_type.value) };
}
break;
}
case "categories": {
if (object.filter_type?.value !== undefined && object.filter_type?.value !== null) {
message.filter_type = {
$case: "categories",
value: ConsumableTankCategoryFilter.fromPartial(object.filter_type.value),
};
}
break;
}
case "nations": {
if (object.filter_type?.value !== undefined && object.filter_type?.value !== null) {
message.filter_type = {
$case: "nations",
value: ConsumableTankNationFilter.fromPartial(object.filter_type.value),
};
}
break;
}
}
return message;
},
};
export function createBaseConsumableTankTierFilter(): ConsumableTankTierFilter {
function createBaseConsumableTankTierFilter(): ConsumableTankTierFilter {
return { min: 0, max: 0 };
}
@@ -581,7 +578,7 @@ export const ConsumableTankTierFilter: MessageFns<ConsumableTankTierFilter> = {
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableTankTierFilter {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableTankTierFilter();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -613,8 +610,8 @@ export const ConsumableTankTierFilter: MessageFns<ConsumableTankTierFilter> = {
fromJSON(object: any): ConsumableTankTierFilter {
return {
min: globalThis.Number(assertSet("ConsumableTankTierFilter.min", object.min)),
max: globalThis.Number(assertSet("ConsumableTankTierFilter.max", object.max)),
min: isSet(object.min) ? globalThis.Number(object.min) : 0,
max: isSet(object.max) ? globalThis.Number(object.max) : 0,
};
},
@@ -640,23 +637,21 @@ export const ConsumableTankTierFilter: MessageFns<ConsumableTankTierFilter> = {
},
};
export function createBaseConsumableTankIdsFilter(): ConsumableTankIdsFilter {
function createBaseConsumableTankIdsFilter(): ConsumableTankIdsFilter {
return { ids: [] };
}
export const ConsumableTankIdsFilter: MessageFns<ConsumableTankIdsFilter> = {
encode(message: ConsumableTankIdsFilter, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
writer.uint32(10).fork();
for (const v of message.ids) {
writer.uint32(v);
writer.uint32(8).uint32(v!);
}
writer.join();
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableTankIdsFilter {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableTankIdsFilter();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -710,23 +705,21 @@ export const ConsumableTankIdsFilter: MessageFns<ConsumableTankIdsFilter> = {
},
};
export function createBaseConsumableTankCategoryFilter(): ConsumableTankCategoryFilter {
function createBaseConsumableTankCategoryFilter(): ConsumableTankCategoryFilter {
return { categories: [] };
}
export const ConsumableTankCategoryFilter: MessageFns<ConsumableTankCategoryFilter> = {
encode(message: ConsumableTankCategoryFilter, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
writer.uint32(10).fork();
for (const v of message.categories) {
writer.int32(v);
writer.uint32(8).int32(v!);
}
writer.join();
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableTankCategoryFilter {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableTankCategoryFilter();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -784,7 +777,7 @@ export const ConsumableTankCategoryFilter: MessageFns<ConsumableTankCategoryFilt
},
};
export function createBaseConsumableTankNationFilter(): ConsumableTankNationFilter {
function createBaseConsumableTankNationFilter(): ConsumableTankNationFilter {
return { nations: [] };
}
@@ -798,7 +791,7 @@ export const ConsumableTankNationFilter: MessageFns<ConsumableTankNationFilter>
decode(input: BinaryReader | Uint8Array, length?: number): ConsumableTankNationFilter {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseConsumableTankNationFilter();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -865,14 +858,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -2,15 +2,15 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message EquipmentDefinitions {
map<string, EquipmentPreset> presets = 1;
map<uint32, Equipment> equipments = 2;
map<string, EquipmentPreset> presets = 1;
map<uint32, Equipment> equipments = 2;
}
message Equipment {
required I18nString name = 1;
required I18nString name = 1;
required I18nString description = 2;
}
@@ -19,6 +19,6 @@ message EquipmentPreset {
}
message EquipmentSlot {
required uint32 left = 1;
required uint32 left = 1;
required uint32 right = 2;
}
@@ -1,12 +1,12 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/equipment_definitions.proto
// source: equipment_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
@@ -26,8 +26,8 @@ export interface EquipmentDefinitions_EquipmentsEntry {
}
export interface Equipment {
name: I18nString;
description: I18nString;
name: I18nString | undefined;
description: I18nString | undefined;
}
export interface EquipmentPreset {
@@ -39,16 +39,16 @@ export interface EquipmentSlot {
right: number;
}
export function createBaseEquipmentDefinitions(): EquipmentDefinitions {
function createBaseEquipmentDefinitions(): EquipmentDefinitions {
return { presets: {}, equipments: {} };
}
export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
encode(message: EquipmentDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.presets).forEach(([key, value]) => {
globalThis.Object.entries(message.presets).forEach(([key, value]: [string, EquipmentPreset]) => {
EquipmentDefinitions_PresetsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
Object.entries(message.equipments).forEach(([key, value]) => {
globalThis.Object.entries(message.equipments).forEach(([key, value]: [string, Equipment]) => {
EquipmentDefinitions_EquipmentsEntry.encode({ key: key as any, value }, writer.uint32(18).fork()).join();
});
return writer;
@@ -56,7 +56,7 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): EquipmentDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipmentDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -95,16 +95,22 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
fromJSON(object: any): EquipmentDefinitions {
return {
presets: isObject(object.presets)
? Object.entries(object.presets).reduce<{ [key: string]: EquipmentPreset }>((acc, [key, value]) => {
acc[key] = EquipmentPreset.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.presets) as [string, any][]).reduce(
(acc: { [key: string]: EquipmentPreset }, [key, value]: [string, any]) => {
acc[key] = EquipmentPreset.fromJSON(value);
return acc;
},
{},
)
: {},
equipments: isObject(object.equipments)
? Object.entries(object.equipments).reduce<{ [key: number]: Equipment }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = Equipment.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.equipments) as [string, any][]).reduce(
(acc: { [key: number]: Equipment }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Equipment.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -112,7 +118,7 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
toJSON(message: EquipmentDefinitions): unknown {
const obj: any = {};
if (message.presets) {
const entries = Object.entries(message.presets);
const entries = globalThis.Object.entries(message.presets) as [string, EquipmentPreset][];
if (entries.length > 0) {
obj.presets = {};
entries.forEach(([k, v]) => {
@@ -121,7 +127,7 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
}
}
if (message.equipments) {
const entries = Object.entries(message.equipments);
const entries = globalThis.Object.entries(message.equipments) as [string, Equipment][];
if (entries.length > 0) {
obj.equipments = {};
entries.forEach(([k, v]) => {
@@ -137,8 +143,8 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<EquipmentDefinitions>, I>>(object: I): EquipmentDefinitions {
const message = createBaseEquipmentDefinitions();
message.presets = Object.entries(object.presets ?? {}).reduce<{ [key: string]: EquipmentPreset }>(
(acc, [key, value]) => {
message.presets = (globalThis.Object.entries(object.presets ?? {}) as [string, EquipmentPreset][]).reduce(
(acc: { [key: string]: EquipmentPreset }, [key, value]: [string, EquipmentPreset]) => {
if (value !== undefined) {
acc[key] = EquipmentPreset.fromPartial(value);
}
@@ -146,8 +152,8 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
},
{},
);
message.equipments = Object.entries(object.equipments ?? {}).reduce<{ [key: number]: Equipment }>(
(acc, [key, value]) => {
message.equipments = (globalThis.Object.entries(object.equipments ?? {}) as [string, Equipment][]).reduce(
(acc: { [key: number]: Equipment }, [key, value]: [string, Equipment]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Equipment.fromPartial(value);
}
@@ -159,13 +165,13 @@ export const EquipmentDefinitions: MessageFns<EquipmentDefinitions> = {
},
};
export function createBaseEquipmentDefinitions_PresetsEntry(): EquipmentDefinitions_PresetsEntry {
return { key: "", value: createBaseEquipmentPreset() };
function createBaseEquipmentDefinitions_PresetsEntry(): EquipmentDefinitions_PresetsEntry {
return { key: "", value: undefined };
}
export const EquipmentDefinitions_PresetsEntry: MessageFns<EquipmentDefinitions_PresetsEntry> = {
encode(message: EquipmentDefinitions_PresetsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== "") {
writer.uint32(10).string(message.key);
}
if (message.value !== undefined) {
@@ -176,7 +182,7 @@ export const EquipmentDefinitions_PresetsEntry: MessageFns<EquipmentDefinitions_
decode(input: BinaryReader | Uint8Array, length?: number): EquipmentDefinitions_PresetsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipmentDefinitions_PresetsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -208,14 +214,14 @@ export const EquipmentDefinitions_PresetsEntry: MessageFns<EquipmentDefinitions_
fromJSON(object: any): EquipmentDefinitions_PresetsEntry {
return {
key: globalThis.String(assertSet("EquipmentDefinitions_PresetsEntry.key", object.key)),
value: EquipmentPreset.fromJSON(assertSet("EquipmentDefinitions_PresetsEntry.value", object.value)),
key: isSet(object.key) ? globalThis.String(object.key) : "",
value: isSet(object.value) ? EquipmentPreset.fromJSON(object.value) : undefined,
};
},
toJSON(message: EquipmentDefinitions_PresetsEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== "") {
obj.key = message.key;
}
if (message.value !== undefined) {
@@ -236,18 +242,18 @@ export const EquipmentDefinitions_PresetsEntry: MessageFns<EquipmentDefinitions_
message.key = object.key ?? "";
message.value = (object.value !== undefined && object.value !== null)
? EquipmentPreset.fromPartial(object.value)
: createBaseEquipmentPreset();
: undefined;
return message;
},
};
export function createBaseEquipmentDefinitions_EquipmentsEntry(): EquipmentDefinitions_EquipmentsEntry {
return { key: 0, value: createBaseEquipment() };
function createBaseEquipmentDefinitions_EquipmentsEntry(): EquipmentDefinitions_EquipmentsEntry {
return { key: 0, value: undefined };
}
export const EquipmentDefinitions_EquipmentsEntry: MessageFns<EquipmentDefinitions_EquipmentsEntry> = {
encode(message: EquipmentDefinitions_EquipmentsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -258,7 +264,7 @@ export const EquipmentDefinitions_EquipmentsEntry: MessageFns<EquipmentDefinitio
decode(input: BinaryReader | Uint8Array, length?: number): EquipmentDefinitions_EquipmentsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipmentDefinitions_EquipmentsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -290,14 +296,14 @@ export const EquipmentDefinitions_EquipmentsEntry: MessageFns<EquipmentDefinitio
fromJSON(object: any): EquipmentDefinitions_EquipmentsEntry {
return {
key: globalThis.Number(assertSet("EquipmentDefinitions_EquipmentsEntry.key", object.key)),
value: Equipment.fromJSON(assertSet("EquipmentDefinitions_EquipmentsEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Equipment.fromJSON(object.value) : undefined,
};
},
toJSON(message: EquipmentDefinitions_EquipmentsEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -318,13 +324,13 @@ export const EquipmentDefinitions_EquipmentsEntry: MessageFns<EquipmentDefinitio
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Equipment.fromPartial(object.value)
: createBaseEquipment();
: undefined;
return message;
},
};
export function createBaseEquipment(): Equipment {
return { name: createBaseI18nString(), description: createBaseI18nString() };
function createBaseEquipment(): Equipment {
return { name: undefined, description: undefined };
}
export const Equipment: MessageFns<Equipment> = {
@@ -340,7 +346,7 @@ export const Equipment: MessageFns<Equipment> = {
decode(input: BinaryReader | Uint8Array, length?: number): Equipment {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipment();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -372,8 +378,8 @@ export const Equipment: MessageFns<Equipment> = {
fromJSON(object: any): Equipment {
return {
name: I18nString.fromJSON(assertSet("Equipment.name", object.name)),
description: I18nString.fromJSON(assertSet("Equipment.description", object.description)),
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
description: isSet(object.description) ? I18nString.fromJSON(object.description) : undefined,
};
},
@@ -395,15 +401,15 @@ export const Equipment: MessageFns<Equipment> = {
const message = createBaseEquipment();
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
: undefined;
message.description = (object.description !== undefined && object.description !== null)
? I18nString.fromPartial(object.description)
: createBaseI18nString();
: undefined;
return message;
},
};
export function createBaseEquipmentPreset(): EquipmentPreset {
function createBaseEquipmentPreset(): EquipmentPreset {
return { slots: [] };
}
@@ -417,7 +423,7 @@ export const EquipmentPreset: MessageFns<EquipmentPreset> = {
decode(input: BinaryReader | Uint8Array, length?: number): EquipmentPreset {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipmentPreset();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -463,7 +469,7 @@ export const EquipmentPreset: MessageFns<EquipmentPreset> = {
},
};
export function createBaseEquipmentSlot(): EquipmentSlot {
function createBaseEquipmentSlot(): EquipmentSlot {
return { left: 0, right: 0 };
}
@@ -480,7 +486,7 @@ export const EquipmentSlot: MessageFns<EquipmentSlot> = {
decode(input: BinaryReader | Uint8Array, length?: number): EquipmentSlot {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEquipmentSlot();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -512,8 +518,8 @@ export const EquipmentSlot: MessageFns<EquipmentSlot> = {
fromJSON(object: any): EquipmentSlot {
return {
left: globalThis.Number(assertSet("EquipmentSlot.left", object.left)),
right: globalThis.Number(assertSet("EquipmentSlot.right", object.right)),
left: isSet(object.left) ? globalThis.Number(object.left) : 0,
right: isSet(object.right) ? globalThis.Number(object.right) : 0,
};
},
@@ -560,14 +566,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+4 -4
View File
@@ -2,14 +2,14 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message Gallery {
repeated Avatar avatars = 1;
}
message Avatar {
required string id = 1;
required I18nString name = 2;
required string extension = 3;
required string id = 1;
required I18nString name = 2;
required string extension = 3;
}
+13 -21
View File
@@ -1,12 +1,12 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/gallery.proto
// source: gallery.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
@@ -16,11 +16,11 @@ export interface Gallery {
export interface Avatar {
id: string;
name: I18nString;
name: I18nString | undefined;
extension: string;
}
export function createBaseGallery(): Gallery {
function createBaseGallery(): Gallery {
return { avatars: [] };
}
@@ -34,7 +34,7 @@ export const Gallery: MessageFns<Gallery> = {
decode(input: BinaryReader | Uint8Array, length?: number): Gallery {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGallery();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -80,8 +80,8 @@ export const Gallery: MessageFns<Gallery> = {
},
};
export function createBaseAvatar(): Avatar {
return { id: "", name: createBaseI18nString(), extension: "" };
function createBaseAvatar(): Avatar {
return { id: "", name: undefined, extension: "" };
}
export const Avatar: MessageFns<Avatar> = {
@@ -100,7 +100,7 @@ export const Avatar: MessageFns<Avatar> = {
decode(input: BinaryReader | Uint8Array, length?: number): Avatar {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseAvatar();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -140,9 +140,9 @@ export const Avatar: MessageFns<Avatar> = {
fromJSON(object: any): Avatar {
return {
id: globalThis.String(assertSet("Avatar.id", object.id)),
name: I18nString.fromJSON(assertSet("Avatar.name", object.name)),
extension: globalThis.String(assertSet("Avatar.extension", object.extension)),
id: isSet(object.id) ? globalThis.String(object.id) : "",
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
extension: isSet(object.extension) ? globalThis.String(object.extension) : "",
};
},
@@ -168,7 +168,7 @@ export const Avatar: MessageFns<Avatar> = {
message.id = object.id ?? "";
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
: undefined;
message.extension = object.extension ?? "";
return message;
},
@@ -191,14 +191,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -2,13 +2,13 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message GameDefinitions {
required string version = 1;
repeated string nations = 2;
map<uint32, GameMode> gameModes = 3;
map<uint32, GameModeRole> roles = 4;
required string version = 1;
repeated string nations = 2;
map<uint32, GameMode> gameModes = 3;
map<uint32, GameModeRole> roles = 4;
}
message GameMode {
@@ -16,6 +16,6 @@ message GameMode {
}
message GameModeRole {
repeated uint32 provisions = 1;
repeated uint32 provisions = 1;
repeated uint32 consumables = 2;
}
+61 -64
View File
@@ -1,12 +1,12 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/game_definitions.proto
// source: game_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
@@ -28,7 +28,7 @@ export interface GameDefinitions_RolesEntry {
}
export interface GameMode {
name: I18nString;
name: I18nString | undefined;
}
export interface GameModeRole {
@@ -36,7 +36,7 @@ export interface GameModeRole {
consumables: number[];
}
export function createBaseGameDefinitions(): GameDefinitions {
function createBaseGameDefinitions(): GameDefinitions {
return { version: "", nations: [], gameModes: {}, roles: {} };
}
@@ -48,10 +48,10 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
for (const v of message.nations) {
writer.uint32(18).string(v!);
}
Object.entries(message.gameModes).forEach(([key, value]) => {
globalThis.Object.entries(message.gameModes).forEach(([key, value]: [string, GameMode]) => {
GameDefinitions_GameModesEntry.encode({ key: key as any, value }, writer.uint32(26).fork()).join();
});
Object.entries(message.roles).forEach(([key, value]) => {
globalThis.Object.entries(message.roles).forEach(([key, value]: [string, GameModeRole]) => {
GameDefinitions_RolesEntry.encode({ key: key as any, value }, writer.uint32(34).fork()).join();
});
return writer;
@@ -59,7 +59,7 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): GameDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGameDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -113,19 +113,25 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
fromJSON(object: any): GameDefinitions {
return {
version: globalThis.String(assertSet("GameDefinitions.version", object.version)),
version: isSet(object.version) ? globalThis.String(object.version) : "",
nations: globalThis.Array.isArray(object?.nations) ? object.nations.map((e: any) => globalThis.String(e)) : [],
gameModes: isObject(object.gameModes)
? Object.entries(object.gameModes).reduce<{ [key: number]: GameMode }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = GameMode.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.gameModes) as [string, any][]).reduce(
(acc: { [key: number]: GameMode }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = GameMode.fromJSON(value);
return acc;
},
{},
)
: {},
roles: isObject(object.roles)
? Object.entries(object.roles).reduce<{ [key: number]: GameModeRole }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = GameModeRole.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.roles) as [string, any][]).reduce(
(acc: { [key: number]: GameModeRole }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = GameModeRole.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -139,7 +145,7 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
obj.nations = message.nations;
}
if (message.gameModes) {
const entries = Object.entries(message.gameModes);
const entries = globalThis.Object.entries(message.gameModes) as [string, GameMode][];
if (entries.length > 0) {
obj.gameModes = {};
entries.forEach(([k, v]) => {
@@ -148,7 +154,7 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
}
}
if (message.roles) {
const entries = Object.entries(message.roles);
const entries = globalThis.Object.entries(message.roles) as [string, GameModeRole][];
if (entries.length > 0) {
obj.roles = {};
entries.forEach(([k, v]) => {
@@ -166,8 +172,8 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
const message = createBaseGameDefinitions();
message.version = object.version ?? "";
message.nations = object.nations?.map((e) => e) || [];
message.gameModes = Object.entries(object.gameModes ?? {}).reduce<{ [key: number]: GameMode }>(
(acc, [key, value]) => {
message.gameModes = (globalThis.Object.entries(object.gameModes ?? {}) as [string, GameMode][]).reduce(
(acc: { [key: number]: GameMode }, [key, value]: [string, GameMode]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = GameMode.fromPartial(value);
}
@@ -175,23 +181,26 @@ export const GameDefinitions: MessageFns<GameDefinitions> = {
},
{},
);
message.roles = Object.entries(object.roles ?? {}).reduce<{ [key: number]: GameModeRole }>((acc, [key, value]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = GameModeRole.fromPartial(value);
}
return acc;
}, {});
message.roles = (globalThis.Object.entries(object.roles ?? {}) as [string, GameModeRole][]).reduce(
(acc: { [key: number]: GameModeRole }, [key, value]: [string, GameModeRole]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = GameModeRole.fromPartial(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseGameDefinitions_GameModesEntry(): GameDefinitions_GameModesEntry {
return { key: 0, value: createBaseGameMode() };
function createBaseGameDefinitions_GameModesEntry(): GameDefinitions_GameModesEntry {
return { key: 0, value: undefined };
}
export const GameDefinitions_GameModesEntry: MessageFns<GameDefinitions_GameModesEntry> = {
encode(message: GameDefinitions_GameModesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -202,7 +211,7 @@ export const GameDefinitions_GameModesEntry: MessageFns<GameDefinitions_GameMode
decode(input: BinaryReader | Uint8Array, length?: number): GameDefinitions_GameModesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGameDefinitions_GameModesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -234,14 +243,14 @@ export const GameDefinitions_GameModesEntry: MessageFns<GameDefinitions_GameMode
fromJSON(object: any): GameDefinitions_GameModesEntry {
return {
key: globalThis.Number(assertSet("GameDefinitions_GameModesEntry.key", object.key)),
value: GameMode.fromJSON(assertSet("GameDefinitions_GameModesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? GameMode.fromJSON(object.value) : undefined,
};
},
toJSON(message: GameDefinitions_GameModesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -260,18 +269,18 @@ export const GameDefinitions_GameModesEntry: MessageFns<GameDefinitions_GameMode
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? GameMode.fromPartial(object.value)
: createBaseGameMode();
: undefined;
return message;
},
};
export function createBaseGameDefinitions_RolesEntry(): GameDefinitions_RolesEntry {
return { key: 0, value: createBaseGameModeRole() };
function createBaseGameDefinitions_RolesEntry(): GameDefinitions_RolesEntry {
return { key: 0, value: undefined };
}
export const GameDefinitions_RolesEntry: MessageFns<GameDefinitions_RolesEntry> = {
encode(message: GameDefinitions_RolesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -282,7 +291,7 @@ export const GameDefinitions_RolesEntry: MessageFns<GameDefinitions_RolesEntry>
decode(input: BinaryReader | Uint8Array, length?: number): GameDefinitions_RolesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGameDefinitions_RolesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -314,14 +323,14 @@ export const GameDefinitions_RolesEntry: MessageFns<GameDefinitions_RolesEntry>
fromJSON(object: any): GameDefinitions_RolesEntry {
return {
key: globalThis.Number(assertSet("GameDefinitions_RolesEntry.key", object.key)),
value: GameModeRole.fromJSON(assertSet("GameDefinitions_RolesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? GameModeRole.fromJSON(object.value) : undefined,
};
},
toJSON(message: GameDefinitions_RolesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -338,13 +347,13 @@ export const GameDefinitions_RolesEntry: MessageFns<GameDefinitions_RolesEntry>
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? GameModeRole.fromPartial(object.value)
: createBaseGameModeRole();
: undefined;
return message;
},
};
export function createBaseGameMode(): GameMode {
return { name: createBaseI18nString() };
function createBaseGameMode(): GameMode {
return { name: undefined };
}
export const GameMode: MessageFns<GameMode> = {
@@ -357,7 +366,7 @@ export const GameMode: MessageFns<GameMode> = {
decode(input: BinaryReader | Uint8Array, length?: number): GameMode {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGameMode();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -380,7 +389,7 @@ export const GameMode: MessageFns<GameMode> = {
},
fromJSON(object: any): GameMode {
return { name: I18nString.fromJSON(assertSet("GameMode.name", object.name)) };
return { name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined };
},
toJSON(message: GameMode): unknown {
@@ -398,33 +407,29 @@ export const GameMode: MessageFns<GameMode> = {
const message = createBaseGameMode();
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
: undefined;
return message;
},
};
export function createBaseGameModeRole(): GameModeRole {
function createBaseGameModeRole(): GameModeRole {
return { provisions: [], consumables: [] };
}
export const GameModeRole: MessageFns<GameModeRole> = {
encode(message: GameModeRole, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
writer.uint32(10).fork();
for (const v of message.provisions) {
writer.uint32(v);
writer.uint32(8).uint32(v!);
}
writer.join();
writer.uint32(18).fork();
for (const v of message.consumables) {
writer.uint32(v);
writer.uint32(16).uint32(v!);
}
writer.join();
return writer;
},
decode(input: BinaryReader | Uint8Array, length?: number): GameModeRole {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseGameModeRole();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -528,14 +533,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+30 -32
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/i18n.proto
// source: i18n.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -18,13 +18,13 @@ export interface I18nString_LocalesEntry {
value: string;
}
export function createBaseI18nString(): I18nString {
function createBaseI18nString(): I18nString {
return { locales: {} };
}
export const I18nString: MessageFns<I18nString> = {
encode(message: I18nString, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.locales).forEach(([key, value]) => {
globalThis.Object.entries(message.locales).forEach(([key, value]: [string, string]) => {
I18nString_LocalesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -32,7 +32,7 @@ export const I18nString: MessageFns<I18nString> = {
decode(input: BinaryReader | Uint8Array, length?: number): I18nString {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseI18nString();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -60,10 +60,13 @@ export const I18nString: MessageFns<I18nString> = {
fromJSON(object: any): I18nString {
return {
locales: isObject(object.locales)
? Object.entries(object.locales).reduce<{ [key: string]: string }>((acc, [key, value]) => {
acc[key] = String(value);
return acc;
}, {})
? (globalThis.Object.entries(object.locales) as [string, any][]).reduce(
(acc: { [key: string]: string }, [key, value]: [string, any]) => {
acc[key] = globalThis.String(value);
return acc;
},
{},
)
: {},
};
},
@@ -71,7 +74,7 @@ export const I18nString: MessageFns<I18nString> = {
toJSON(message: I18nString): unknown {
const obj: any = {};
if (message.locales) {
const entries = Object.entries(message.locales);
const entries = globalThis.Object.entries(message.locales) as [string, string][];
if (entries.length > 0) {
obj.locales = {};
entries.forEach(([k, v]) => {
@@ -87,26 +90,29 @@ export const I18nString: MessageFns<I18nString> = {
},
fromPartial<I extends Exact<DeepPartial<I18nString>, I>>(object: I): I18nString {
const message = createBaseI18nString();
message.locales = Object.entries(object.locales ?? {}).reduce<{ [key: string]: string }>((acc, [key, value]) => {
if (value !== undefined) {
acc[key] = globalThis.String(value);
}
return acc;
}, {});
message.locales = (globalThis.Object.entries(object.locales ?? {}) as [string, string][]).reduce(
(acc: { [key: string]: string }, [key, value]: [string, string]) => {
if (value !== undefined) {
acc[key] = globalThis.String(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseI18nString_LocalesEntry(): I18nString_LocalesEntry {
function createBaseI18nString_LocalesEntry(): I18nString_LocalesEntry {
return { key: "", value: "" };
}
export const I18nString_LocalesEntry: MessageFns<I18nString_LocalesEntry> = {
encode(message: I18nString_LocalesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== "") {
writer.uint32(10).string(message.key);
}
if (message.value !== undefined) {
if (message.value !== "") {
writer.uint32(18).string(message.value);
}
return writer;
@@ -114,7 +120,7 @@ export const I18nString_LocalesEntry: MessageFns<I18nString_LocalesEntry> = {
decode(input: BinaryReader | Uint8Array, length?: number): I18nString_LocalesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseI18nString_LocalesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -146,17 +152,17 @@ export const I18nString_LocalesEntry: MessageFns<I18nString_LocalesEntry> = {
fromJSON(object: any): I18nString_LocalesEntry {
return {
key: globalThis.String(assertSet("I18nString_LocalesEntry.key", object.key)),
value: globalThis.String(assertSet("I18nString_LocalesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.String(object.key) : "",
value: isSet(object.value) ? globalThis.String(object.value) : "",
};
},
toJSON(message: I18nString_LocalesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== "") {
obj.key = message.key;
}
if (message.value !== undefined) {
if (message.value !== "") {
obj.value = message.value;
}
return obj;
@@ -194,14 +200,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+15 -15
View File
@@ -1,16 +1,16 @@
// @ts-nocheck
export * from './average_definitions.ts';
export * from './camouflage_definitions.ts';
export * from './consumable_definitions.ts';
export * from './equipment_definitions.ts';
export * from './gallery.ts';
export * from './game_definitions.ts';
export * from './i18n.ts';
export * from './map_definitions.ts';
export * from './model_definitions.ts';
export * from './popular_tanks.ts';
export * from './provision_definitions.ts';
export * from './rating_leaderboard.ts';
export * from './reviews.ts';
export * from './skill_definitions.ts';
export * from './tank_definitions.ts';
export * from "./average_definitions.ts";
export * from "./camouflage_definitions.ts";
export * from "./consumable_definitions.ts";
export * from "./equipment_definitions.ts";
export * from "./gallery.ts";
export * from "./game_definitions.ts";
export * from "./i18n.ts";
export * from "./map_definitions.ts";
export * from "./model_definitions.ts";
export * from "./popular_tanks.ts";
export * from "./provision_definitions.ts";
export * from "./rating_leaderboard.ts";
export * from "./reviews.ts";
export * from "./skill_definitions.ts";
export * from "./tank_definitions.ts";
@@ -2,13 +2,13 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message MapDefinitions {
map<int32, MapDefinition> maps = 1;
}
message MapDefinition {
required uint32 id = 1;
required uint32 id = 1;
required I18nString name = 2;
}
+38 -40
View File
@@ -1,12 +1,12 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/map_definitions.proto
// source: map_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
@@ -21,16 +21,16 @@ export interface MapDefinitions_MapsEntry {
export interface MapDefinition {
id: number;
name: I18nString;
name: I18nString | undefined;
}
export function createBaseMapDefinitions(): MapDefinitions {
function createBaseMapDefinitions(): MapDefinitions {
return { maps: {} };
}
export const MapDefinitions: MessageFns<MapDefinitions> = {
encode(message: MapDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.maps).forEach(([key, value]) => {
globalThis.Object.entries(message.maps).forEach(([key, value]: [string, MapDefinition]) => {
MapDefinitions_MapsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -38,7 +38,7 @@ export const MapDefinitions: MessageFns<MapDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): MapDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseMapDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -66,10 +66,13 @@ export const MapDefinitions: MessageFns<MapDefinitions> = {
fromJSON(object: any): MapDefinitions {
return {
maps: isObject(object.maps)
? Object.entries(object.maps).reduce<{ [key: number]: MapDefinition }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = MapDefinition.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.maps) as [string, any][]).reduce(
(acc: { [key: number]: MapDefinition }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = MapDefinition.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -77,7 +80,7 @@ export const MapDefinitions: MessageFns<MapDefinitions> = {
toJSON(message: MapDefinitions): unknown {
const obj: any = {};
if (message.maps) {
const entries = Object.entries(message.maps);
const entries = globalThis.Object.entries(message.maps) as [string, MapDefinition][];
if (entries.length > 0) {
obj.maps = {};
entries.forEach(([k, v]) => {
@@ -93,23 +96,26 @@ export const MapDefinitions: MessageFns<MapDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<MapDefinitions>, I>>(object: I): MapDefinitions {
const message = createBaseMapDefinitions();
message.maps = Object.entries(object.maps ?? {}).reduce<{ [key: number]: MapDefinition }>((acc, [key, value]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = MapDefinition.fromPartial(value);
}
return acc;
}, {});
message.maps = (globalThis.Object.entries(object.maps ?? {}) as [string, MapDefinition][]).reduce(
(acc: { [key: number]: MapDefinition }, [key, value]: [string, MapDefinition]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = MapDefinition.fromPartial(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseMapDefinitions_MapsEntry(): MapDefinitions_MapsEntry {
return { key: 0, value: createBaseMapDefinition() };
function createBaseMapDefinitions_MapsEntry(): MapDefinitions_MapsEntry {
return { key: 0, value: undefined };
}
export const MapDefinitions_MapsEntry: MessageFns<MapDefinitions_MapsEntry> = {
encode(message: MapDefinitions_MapsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).int32(message.key);
}
if (message.value !== undefined) {
@@ -120,7 +126,7 @@ export const MapDefinitions_MapsEntry: MessageFns<MapDefinitions_MapsEntry> = {
decode(input: BinaryReader | Uint8Array, length?: number): MapDefinitions_MapsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseMapDefinitions_MapsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -152,14 +158,14 @@ export const MapDefinitions_MapsEntry: MessageFns<MapDefinitions_MapsEntry> = {
fromJSON(object: any): MapDefinitions_MapsEntry {
return {
key: globalThis.Number(assertSet("MapDefinitions_MapsEntry.key", object.key)),
value: MapDefinition.fromJSON(assertSet("MapDefinitions_MapsEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? MapDefinition.fromJSON(object.value) : undefined,
};
},
toJSON(message: MapDefinitions_MapsEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -176,13 +182,13 @@ export const MapDefinitions_MapsEntry: MessageFns<MapDefinitions_MapsEntry> = {
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? MapDefinition.fromPartial(object.value)
: createBaseMapDefinition();
: undefined;
return message;
},
};
export function createBaseMapDefinition(): MapDefinition {
return { id: 0, name: createBaseI18nString() };
function createBaseMapDefinition(): MapDefinition {
return { id: 0, name: undefined };
}
export const MapDefinition: MessageFns<MapDefinition> = {
@@ -198,7 +204,7 @@ export const MapDefinition: MessageFns<MapDefinition> = {
decode(input: BinaryReader | Uint8Array, length?: number): MapDefinition {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseMapDefinition();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -230,8 +236,8 @@ export const MapDefinition: MessageFns<MapDefinition> = {
fromJSON(object: any): MapDefinition {
return {
id: globalThis.Number(assertSet("MapDefinition.id", object.id)),
name: I18nString.fromJSON(assertSet("MapDefinition.name", object.name)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
};
},
@@ -254,7 +260,7 @@ export const MapDefinition: MessageFns<MapDefinition> = {
message.id = object.id ?? 0;
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
: undefined;
return message;
},
};
@@ -280,14 +286,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -7,17 +7,17 @@ message ModelDefinitions {
}
message ModelDefinition {
required Armor armor = 1;
required Vector3 turret_origin = 2;
optional InitialTurretRotation initial_turret_rotation = 3;
map<uint32, TurretModelDefinition> turrets = 4;
map<uint32, TrackModelDefinition> tracks = 5;
required BoundingBox bounding_box = 6;
required Armor armor = 1;
required Vector3 turret_origin = 2;
optional InitialTurretRotation initial_turret_rotation = 3;
map<uint32, TurretModelDefinition> turrets = 4;
map<uint32, TrackModelDefinition> tracks = 5;
required BoundingBox bounding_box = 6;
}
message Armor {
map<uint32, float> thickness = 1;
repeated uint32 spaced = 2;
repeated uint32 spaced = 2;
}
message Vector3 {
@@ -27,18 +27,18 @@ message Vector3 {
}
message InitialTurretRotation {
required float yaw = 1;
required float yaw = 1;
required float pitch = 2;
required float roll = 3;
required float roll = 3;
}
message TurretModelDefinition {
required BoundingBox bounding_box = 1;
required Armor armor = 2;
required uint32 model_id = 3;
required Vector3 gun_origin = 4;
map<uint32, GunModelDefinition> guns = 5;
optional YawLimits yaw = 6;
required BoundingBox bounding_box = 1;
required Armor armor = 2;
required uint32 model_id = 3;
required Vector3 gun_origin = 4;
map<uint32, GunModelDefinition> guns = 5;
optional YawLimits yaw = 6;
}
message YawLimits {
@@ -52,28 +52,28 @@ message BoundingBox {
}
message TrackModelDefinition {
required float thickness = 1;
required Vector3 origin = 2;
required float thickness = 1;
required Vector3 origin = 2;
}
message GunModelDefinition {
required Armor armor = 1;
required float thickness = 2;
required uint32 model_id = 3;
required PitchLimits pitch = 4;
optional float mask = 5;
required Armor armor = 1;
required float thickness = 2;
required uint32 model_id = 3;
required PitchLimits pitch = 4;
optional float mask = 5;
}
message PitchLimits {
required float min = 1;
required float max = 2;
optional PitchLimitsExtrema front = 3;
optional PitchLimitsExtrema back = 4;
optional float transition = 5;
required float min = 1;
required float max = 2;
optional PitchLimitsExtrema front = 3;
optional PitchLimitsExtrema back = 4;
optional float transition = 5;
}
message PitchLimitsExtrema {
required float min = 1;
required float max = 2;
required float min = 1;
required float max = 2;
required float range = 3;
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -7,6 +7,6 @@ message PopularTanks {
}
message PopularTank {
required uint32 id = 1;
required uint32 id = 1;
required uint32 views = 2; // views in the last 7 days
}
+8 -16
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/popular_tanks.proto
// source: popular_tanks.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -19,7 +19,7 @@ export interface PopularTank {
views: number;
}
export function createBasePopularTanks(): PopularTanks {
function createBasePopularTanks(): PopularTanks {
return { tanks: [] };
}
@@ -33,7 +33,7 @@ export const PopularTanks: MessageFns<PopularTanks> = {
decode(input: BinaryReader | Uint8Array, length?: number): PopularTanks {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBasePopularTanks();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -79,7 +79,7 @@ export const PopularTanks: MessageFns<PopularTanks> = {
},
};
export function createBasePopularTank(): PopularTank {
function createBasePopularTank(): PopularTank {
return { id: 0, views: 0 };
}
@@ -96,7 +96,7 @@ export const PopularTank: MessageFns<PopularTank> = {
decode(input: BinaryReader | Uint8Array, length?: number): PopularTank {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBasePopularTank();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -128,8 +128,8 @@ export const PopularTank: MessageFns<PopularTank> = {
fromJSON(object: any): PopularTank {
return {
id: globalThis.Number(assertSet("PopularTank.id", object.id)),
views: globalThis.Number(assertSet("PopularTank.views", object.views)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
views: isSet(object.views) ? globalThis.Number(object.views) : 0,
};
},
@@ -172,14 +172,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -2,18 +2,18 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/consumable_definitions.proto";
import "packages/core/src/protos/i18n.proto";
import "consumable_definitions.proto";
import "i18n.proto";
message ProvisionDefinitions {
map<uint32, Provision> provisions = 1;
}
message Provision {
required uint32 id = 1;
required I18nString name = 2;
optional float crew = 3;
required bool game_mode_exclusive = 5;
repeated ConsumableTankFilter include = 6;
repeated ConsumableTankFilter exclude = 7;
required uint32 id = 1;
required I18nString name = 2;
optional float crew = 3;
required bool game_mode_exclusive = 5;
repeated ConsumableTankFilter include = 6;
repeated ConsumableTankFilter exclude = 7;
}
@@ -1,13 +1,13 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/provision_definitions.proto
// source: provision_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
import { ConsumableTankFilter } from "./consumable_definitions";
import { createBaseI18nString, I18nString } from "./i18n";
import { I18nString } from "./i18n";
export const protobufPackage = "blitzkit";
@@ -22,20 +22,20 @@ export interface ProvisionDefinitions_ProvisionsEntry {
export interface Provision {
id: number;
name: I18nString;
name: I18nString | undefined;
crew?: number | undefined;
game_mode_exclusive: boolean;
include: ConsumableTankFilter[];
exclude: ConsumableTankFilter[];
}
export function createBaseProvisionDefinitions(): ProvisionDefinitions {
function createBaseProvisionDefinitions(): ProvisionDefinitions {
return { provisions: {} };
}
export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
encode(message: ProvisionDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.provisions).forEach(([key, value]) => {
globalThis.Object.entries(message.provisions).forEach(([key, value]: [string, Provision]) => {
ProvisionDefinitions_ProvisionsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -43,7 +43,7 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): ProvisionDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseProvisionDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -71,10 +71,13 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
fromJSON(object: any): ProvisionDefinitions {
return {
provisions: isObject(object.provisions)
? Object.entries(object.provisions).reduce<{ [key: number]: Provision }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = Provision.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.provisions) as [string, any][]).reduce(
(acc: { [key: number]: Provision }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Provision.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -82,7 +85,7 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
toJSON(message: ProvisionDefinitions): unknown {
const obj: any = {};
if (message.provisions) {
const entries = Object.entries(message.provisions);
const entries = globalThis.Object.entries(message.provisions) as [string, Provision][];
if (entries.length > 0) {
obj.provisions = {};
entries.forEach(([k, v]) => {
@@ -98,8 +101,8 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<ProvisionDefinitions>, I>>(object: I): ProvisionDefinitions {
const message = createBaseProvisionDefinitions();
message.provisions = Object.entries(object.provisions ?? {}).reduce<{ [key: number]: Provision }>(
(acc, [key, value]) => {
message.provisions = (globalThis.Object.entries(object.provisions ?? {}) as [string, Provision][]).reduce(
(acc: { [key: number]: Provision }, [key, value]: [string, Provision]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Provision.fromPartial(value);
}
@@ -111,13 +114,13 @@ export const ProvisionDefinitions: MessageFns<ProvisionDefinitions> = {
},
};
export function createBaseProvisionDefinitions_ProvisionsEntry(): ProvisionDefinitions_ProvisionsEntry {
return { key: 0, value: createBaseProvision() };
function createBaseProvisionDefinitions_ProvisionsEntry(): ProvisionDefinitions_ProvisionsEntry {
return { key: 0, value: undefined };
}
export const ProvisionDefinitions_ProvisionsEntry: MessageFns<ProvisionDefinitions_ProvisionsEntry> = {
encode(message: ProvisionDefinitions_ProvisionsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -128,7 +131,7 @@ export const ProvisionDefinitions_ProvisionsEntry: MessageFns<ProvisionDefinitio
decode(input: BinaryReader | Uint8Array, length?: number): ProvisionDefinitions_ProvisionsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseProvisionDefinitions_ProvisionsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -160,14 +163,14 @@ export const ProvisionDefinitions_ProvisionsEntry: MessageFns<ProvisionDefinitio
fromJSON(object: any): ProvisionDefinitions_ProvisionsEntry {
return {
key: globalThis.Number(assertSet("ProvisionDefinitions_ProvisionsEntry.key", object.key)),
value: Provision.fromJSON(assertSet("ProvisionDefinitions_ProvisionsEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Provision.fromJSON(object.value) : undefined,
};
},
toJSON(message: ProvisionDefinitions_ProvisionsEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -188,13 +191,13 @@ export const ProvisionDefinitions_ProvisionsEntry: MessageFns<ProvisionDefinitio
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Provision.fromPartial(object.value)
: createBaseProvision();
: undefined;
return message;
},
};
export function createBaseProvision(): Provision {
return { id: 0, name: createBaseI18nString(), crew: undefined, game_mode_exclusive: false, include: [], exclude: [] };
function createBaseProvision(): Provision {
return { id: 0, name: undefined, crew: 0, game_mode_exclusive: false, include: [], exclude: [] };
}
export const Provision: MessageFns<Provision> = {
@@ -205,7 +208,7 @@ export const Provision: MessageFns<Provision> = {
if (message.name !== undefined) {
I18nString.encode(message.name, writer.uint32(18).fork()).join();
}
if (message.crew !== undefined && message.crew !== undefined) {
if (message.crew !== undefined && message.crew !== 0) {
writer.uint32(29).float(message.crew);
}
if (message.game_mode_exclusive !== false) {
@@ -222,7 +225,7 @@ export const Provision: MessageFns<Provision> = {
decode(input: BinaryReader | Uint8Array, length?: number): Provision {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseProvision();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -286,10 +289,14 @@ export const Provision: MessageFns<Provision> = {
fromJSON(object: any): Provision {
return {
id: globalThis.Number(assertSet("Provision.id", object.id)),
name: I18nString.fromJSON(assertSet("Provision.name", object.name)),
crew: isSet(object.crew) ? globalThis.Number(object.crew) : undefined,
game_mode_exclusive: globalThis.Boolean(assertSet("Provision.game_mode_exclusive", object.game_mode_exclusive)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
name: isSet(object.name) ? I18nString.fromJSON(object.name) : undefined,
crew: isSet(object.crew) ? globalThis.Number(object.crew) : 0,
game_mode_exclusive: isSet(object.gameModeExclusive)
? globalThis.Boolean(object.gameModeExclusive)
: isSet(object.game_mode_exclusive)
? globalThis.Boolean(object.game_mode_exclusive)
: false,
include: globalThis.Array.isArray(object?.include)
? object.include.map((e: any) => ConsumableTankFilter.fromJSON(e))
: [],
@@ -307,11 +314,11 @@ export const Provision: MessageFns<Provision> = {
if (message.name !== undefined) {
obj.name = I18nString.toJSON(message.name);
}
if (message.crew !== undefined && message.crew !== undefined) {
if (message.crew !== undefined && message.crew !== 0) {
obj.crew = message.crew;
}
if (message.game_mode_exclusive !== false) {
obj.game_mode_exclusive = message.game_mode_exclusive;
obj.gameModeExclusive = message.game_mode_exclusive;
}
if (message.include?.length) {
obj.include = message.include.map((e) => ConsumableTankFilter.toJSON(e));
@@ -330,8 +337,8 @@ export const Provision: MessageFns<Provision> = {
message.id = object.id ?? 0;
message.name = (object.name !== undefined && object.name !== null)
? I18nString.fromPartial(object.name)
: createBaseI18nString();
message.crew = object.crew ?? undefined;
: undefined;
message.crew = object.crew ?? 0;
message.game_mode_exclusive = object.game_mode_exclusive ?? false;
message.include = object.include?.map((e) => ConsumableTankFilter.fromPartial(e)) || [];
message.exclude = object.exclude?.map((e) => ConsumableTankFilter.fromPartial(e)) || [];
@@ -360,14 +367,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
@@ -14,7 +14,7 @@ message RatingLeaderboardV1 {
}
message RatingLeaderboardEntryV1 {
required uint32 id = 1;
required uint32 id = 1;
required uint32 score = 2;
}
@@ -23,11 +23,11 @@ message RatingLeaderboardV2 {
}
message RatingLeaderboardEntryV2 {
required uint32 id = 1;
required uint32 score = 2;
required uint32 battles = 3;
required uint32 wins = 4;
required uint32 id = 1;
required uint32 score = 2;
required uint32 battles = 3;
required uint32 wins = 4;
required uint32 survived = 5;
required uint32 damage = 6;
required uint32 kills = 7;
required uint32 damage = 6;
required uint32 kills = 7;
}
+35 -36
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/rating_leaderboard.proto
// source: rating_leaderboard.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -36,7 +36,7 @@ export interface RatingLeaderboardEntryV2 {
kills: number;
}
export function createBaseRatingLeaderboard(): RatingLeaderboard {
function createBaseRatingLeaderboard(): RatingLeaderboard {
return { version: undefined };
}
@@ -55,7 +55,7 @@ export const RatingLeaderboard: MessageFns<RatingLeaderboard> = {
decode(input: BinaryReader | Uint8Array, length?: number): RatingLeaderboard {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseRatingLeaderboard();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -99,8 +99,7 @@ export const RatingLeaderboard: MessageFns<RatingLeaderboard> = {
const obj: any = {};
if (message.version?.$case === "v1") {
obj.v1 = RatingLeaderboardV1.toJSON(message.version.value);
}
if (message.version?.$case === "v2") {
} else if (message.version?.$case === "v2") {
obj.v2 = RatingLeaderboardV2.toJSON(message.version.value);
}
return obj;
@@ -111,17 +110,25 @@ export const RatingLeaderboard: MessageFns<RatingLeaderboard> = {
},
fromPartial<I extends Exact<DeepPartial<RatingLeaderboard>, I>>(object: I): RatingLeaderboard {
const message = createBaseRatingLeaderboard();
if (object.version?.$case === "v1" && object.version?.value !== undefined && object.version?.value !== null) {
message.version = { $case: "v1", value: RatingLeaderboardV1.fromPartial(object.version.value) };
}
if (object.version?.$case === "v2" && object.version?.value !== undefined && object.version?.value !== null) {
message.version = { $case: "v2", value: RatingLeaderboardV2.fromPartial(object.version.value) };
switch (object.version?.$case) {
case "v1": {
if (object.version?.value !== undefined && object.version?.value !== null) {
message.version = { $case: "v1", value: RatingLeaderboardV1.fromPartial(object.version.value) };
}
break;
}
case "v2": {
if (object.version?.value !== undefined && object.version?.value !== null) {
message.version = { $case: "v2", value: RatingLeaderboardV2.fromPartial(object.version.value) };
}
break;
}
}
return message;
},
};
export function createBaseRatingLeaderboardV1(): RatingLeaderboardV1 {
function createBaseRatingLeaderboardV1(): RatingLeaderboardV1 {
return { entries: [] };
}
@@ -135,7 +142,7 @@ export const RatingLeaderboardV1: MessageFns<RatingLeaderboardV1> = {
decode(input: BinaryReader | Uint8Array, length?: number): RatingLeaderboardV1 {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseRatingLeaderboardV1();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -183,7 +190,7 @@ export const RatingLeaderboardV1: MessageFns<RatingLeaderboardV1> = {
},
};
export function createBaseRatingLeaderboardEntryV1(): RatingLeaderboardEntryV1 {
function createBaseRatingLeaderboardEntryV1(): RatingLeaderboardEntryV1 {
return { id: 0, score: 0 };
}
@@ -200,7 +207,7 @@ export const RatingLeaderboardEntryV1: MessageFns<RatingLeaderboardEntryV1> = {
decode(input: BinaryReader | Uint8Array, length?: number): RatingLeaderboardEntryV1 {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseRatingLeaderboardEntryV1();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -232,8 +239,8 @@ export const RatingLeaderboardEntryV1: MessageFns<RatingLeaderboardEntryV1> = {
fromJSON(object: any): RatingLeaderboardEntryV1 {
return {
id: globalThis.Number(assertSet("RatingLeaderboardEntryV1.id", object.id)),
score: globalThis.Number(assertSet("RatingLeaderboardEntryV1.score", object.score)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
score: isSet(object.score) ? globalThis.Number(object.score) : 0,
};
},
@@ -259,7 +266,7 @@ export const RatingLeaderboardEntryV1: MessageFns<RatingLeaderboardEntryV1> = {
},
};
export function createBaseRatingLeaderboardV2(): RatingLeaderboardV2 {
function createBaseRatingLeaderboardV2(): RatingLeaderboardV2 {
return { entries: [] };
}
@@ -273,7 +280,7 @@ export const RatingLeaderboardV2: MessageFns<RatingLeaderboardV2> = {
decode(input: BinaryReader | Uint8Array, length?: number): RatingLeaderboardV2 {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseRatingLeaderboardV2();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -321,7 +328,7 @@ export const RatingLeaderboardV2: MessageFns<RatingLeaderboardV2> = {
},
};
export function createBaseRatingLeaderboardEntryV2(): RatingLeaderboardEntryV2 {
function createBaseRatingLeaderboardEntryV2(): RatingLeaderboardEntryV2 {
return { id: 0, score: 0, battles: 0, wins: 0, survived: 0, damage: 0, kills: 0 };
}
@@ -353,7 +360,7 @@ export const RatingLeaderboardEntryV2: MessageFns<RatingLeaderboardEntryV2> = {
decode(input: BinaryReader | Uint8Array, length?: number): RatingLeaderboardEntryV2 {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseRatingLeaderboardEntryV2();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -425,13 +432,13 @@ export const RatingLeaderboardEntryV2: MessageFns<RatingLeaderboardEntryV2> = {
fromJSON(object: any): RatingLeaderboardEntryV2 {
return {
id: globalThis.Number(assertSet("RatingLeaderboardEntryV2.id", object.id)),
score: globalThis.Number(assertSet("RatingLeaderboardEntryV2.score", object.score)),
battles: globalThis.Number(assertSet("RatingLeaderboardEntryV2.battles", object.battles)),
wins: globalThis.Number(assertSet("RatingLeaderboardEntryV2.wins", object.wins)),
survived: globalThis.Number(assertSet("RatingLeaderboardEntryV2.survived", object.survived)),
damage: globalThis.Number(assertSet("RatingLeaderboardEntryV2.damage", object.damage)),
kills: globalThis.Number(assertSet("RatingLeaderboardEntryV2.kills", object.kills)),
id: isSet(object.id) ? globalThis.Number(object.id) : 0,
score: isSet(object.score) ? globalThis.Number(object.score) : 0,
battles: isSet(object.battles) ? globalThis.Number(object.battles) : 0,
wins: isSet(object.wins) ? globalThis.Number(object.wins) : 0,
survived: isSet(object.survived) ? globalThis.Number(object.survived) : 0,
damage: isSet(object.damage) ? globalThis.Number(object.damage) : 0,
kills: isSet(object.kills) ? globalThis.Number(object.kills) : 0,
};
},
@@ -494,14 +501,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+2 -2
View File
@@ -8,10 +8,10 @@ message Reviews {
message Review {
required float last_updated = 1;
repeated Video videos = 2;
repeated Video videos = 2;
}
message Video {
required string id = 1;
required string id = 1;
required string author = 2;
}
+42 -40
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/reviews.proto
// source: reviews.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -28,13 +28,13 @@ export interface Video {
author: string;
}
export function createBaseReviews(): Reviews {
function createBaseReviews(): Reviews {
return { reviews: {} };
}
export const Reviews: MessageFns<Reviews> = {
encode(message: Reviews, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.reviews).forEach(([key, value]) => {
globalThis.Object.entries(message.reviews).forEach(([key, value]: [string, Review]) => {
Reviews_ReviewsEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -42,7 +42,7 @@ export const Reviews: MessageFns<Reviews> = {
decode(input: BinaryReader | Uint8Array, length?: number): Reviews {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseReviews();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -70,10 +70,13 @@ export const Reviews: MessageFns<Reviews> = {
fromJSON(object: any): Reviews {
return {
reviews: isObject(object.reviews)
? Object.entries(object.reviews).reduce<{ [key: number]: Review }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = Review.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.reviews) as [string, any][]).reduce(
(acc: { [key: number]: Review }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Review.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -81,7 +84,7 @@ export const Reviews: MessageFns<Reviews> = {
toJSON(message: Reviews): unknown {
const obj: any = {};
if (message.reviews) {
const entries = Object.entries(message.reviews);
const entries = globalThis.Object.entries(message.reviews) as [string, Review][];
if (entries.length > 0) {
obj.reviews = {};
entries.forEach(([k, v]) => {
@@ -97,23 +100,26 @@ export const Reviews: MessageFns<Reviews> = {
},
fromPartial<I extends Exact<DeepPartial<Reviews>, I>>(object: I): Reviews {
const message = createBaseReviews();
message.reviews = Object.entries(object.reviews ?? {}).reduce<{ [key: number]: Review }>((acc, [key, value]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Review.fromPartial(value);
}
return acc;
}, {});
message.reviews = (globalThis.Object.entries(object.reviews ?? {}) as [string, Review][]).reduce(
(acc: { [key: number]: Review }, [key, value]: [string, Review]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Review.fromPartial(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseReviews_ReviewsEntry(): Reviews_ReviewsEntry {
return { key: 0, value: createBaseReview() };
function createBaseReviews_ReviewsEntry(): Reviews_ReviewsEntry {
return { key: 0, value: undefined };
}
export const Reviews_ReviewsEntry: MessageFns<Reviews_ReviewsEntry> = {
encode(message: Reviews_ReviewsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -124,7 +130,7 @@ export const Reviews_ReviewsEntry: MessageFns<Reviews_ReviewsEntry> = {
decode(input: BinaryReader | Uint8Array, length?: number): Reviews_ReviewsEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseReviews_ReviewsEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -156,14 +162,14 @@ export const Reviews_ReviewsEntry: MessageFns<Reviews_ReviewsEntry> = {
fromJSON(object: any): Reviews_ReviewsEntry {
return {
key: globalThis.Number(assertSet("Reviews_ReviewsEntry.key", object.key)),
value: Review.fromJSON(assertSet("Reviews_ReviewsEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Review.fromJSON(object.value) : undefined,
};
},
toJSON(message: Reviews_ReviewsEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -180,12 +186,12 @@ export const Reviews_ReviewsEntry: MessageFns<Reviews_ReviewsEntry> = {
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Review.fromPartial(object.value)
: createBaseReview();
: undefined;
return message;
},
};
export function createBaseReview(): Review {
function createBaseReview(): Review {
return { last_updated: 0, videos: [] };
}
@@ -202,7 +208,7 @@ export const Review: MessageFns<Review> = {
decode(input: BinaryReader | Uint8Array, length?: number): Review {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseReview();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -234,7 +240,11 @@ export const Review: MessageFns<Review> = {
fromJSON(object: any): Review {
return {
last_updated: globalThis.Number(assertSet("Review.last_updated", object.last_updated)),
last_updated: isSet(object.lastUpdated)
? globalThis.Number(object.lastUpdated)
: isSet(object.last_updated)
? globalThis.Number(object.last_updated)
: 0,
videos: globalThis.Array.isArray(object?.videos) ? object.videos.map((e: any) => Video.fromJSON(e)) : [],
};
},
@@ -242,7 +252,7 @@ export const Review: MessageFns<Review> = {
toJSON(message: Review): unknown {
const obj: any = {};
if (message.last_updated !== 0) {
obj.last_updated = message.last_updated;
obj.lastUpdated = message.last_updated;
}
if (message.videos?.length) {
obj.videos = message.videos.map((e) => Video.toJSON(e));
@@ -261,7 +271,7 @@ export const Review: MessageFns<Review> = {
},
};
export function createBaseVideo(): Video {
function createBaseVideo(): Video {
return { id: "", author: "" };
}
@@ -278,7 +288,7 @@ export const Video: MessageFns<Video> = {
decode(input: BinaryReader | Uint8Array, length?: number): Video {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseVideo();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -310,8 +320,8 @@ export const Video: MessageFns<Video> = {
fromJSON(object: any): Video {
return {
id: globalThis.String(assertSet("Video.id", object.id)),
author: globalThis.String(assertSet("Video.author", object.author)),
id: isSet(object.id) ? globalThis.String(object.id) : "",
author: isSet(object.author) ? globalThis.String(object.author) : "",
};
},
@@ -358,14 +368,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+32 -36
View File
@@ -1,8 +1,8 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v2.2.2
// protoc-gen-ts_proto v2.11.2
// protoc v5.28.2
// source: packages/core/src/protos/skill_definitions.proto
// source: skill_definitions.proto
/* eslint-disable */
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -23,13 +23,13 @@ export interface Skill {
skills: string[];
}
export function createBaseSkillDefinitions(): SkillDefinitions {
function createBaseSkillDefinitions(): SkillDefinitions {
return { classes: {} };
}
export const SkillDefinitions: MessageFns<SkillDefinitions> = {
encode(message: SkillDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
Object.entries(message.classes).forEach(([key, value]) => {
globalThis.Object.entries(message.classes).forEach(([key, value]: [string, Skill]) => {
SkillDefinitions_ClassesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
});
return writer;
@@ -37,7 +37,7 @@ export const SkillDefinitions: MessageFns<SkillDefinitions> = {
decode(input: BinaryReader | Uint8Array, length?: number): SkillDefinitions {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseSkillDefinitions();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -65,10 +65,13 @@ export const SkillDefinitions: MessageFns<SkillDefinitions> = {
fromJSON(object: any): SkillDefinitions {
return {
classes: isObject(object.classes)
? Object.entries(object.classes).reduce<{ [key: number]: Skill }>((acc, [key, value]) => {
acc[globalThis.Number(key)] = Skill.fromJSON(value);
return acc;
}, {})
? (globalThis.Object.entries(object.classes) as [string, any][]).reduce(
(acc: { [key: number]: Skill }, [key, value]: [string, any]) => {
acc[globalThis.Number(key)] = Skill.fromJSON(value);
return acc;
},
{},
)
: {},
};
},
@@ -76,7 +79,7 @@ export const SkillDefinitions: MessageFns<SkillDefinitions> = {
toJSON(message: SkillDefinitions): unknown {
const obj: any = {};
if (message.classes) {
const entries = Object.entries(message.classes);
const entries = globalThis.Object.entries(message.classes) as [string, Skill][];
if (entries.length > 0) {
obj.classes = {};
entries.forEach(([k, v]) => {
@@ -92,23 +95,26 @@ export const SkillDefinitions: MessageFns<SkillDefinitions> = {
},
fromPartial<I extends Exact<DeepPartial<SkillDefinitions>, I>>(object: I): SkillDefinitions {
const message = createBaseSkillDefinitions();
message.classes = Object.entries(object.classes ?? {}).reduce<{ [key: number]: Skill }>((acc, [key, value]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Skill.fromPartial(value);
}
return acc;
}, {});
message.classes = (globalThis.Object.entries(object.classes ?? {}) as [string, Skill][]).reduce(
(acc: { [key: number]: Skill }, [key, value]: [string, Skill]) => {
if (value !== undefined) {
acc[globalThis.Number(key)] = Skill.fromPartial(value);
}
return acc;
},
{},
);
return message;
},
};
export function createBaseSkillDefinitions_ClassesEntry(): SkillDefinitions_ClassesEntry {
return { key: 0, value: createBaseSkill() };
function createBaseSkillDefinitions_ClassesEntry(): SkillDefinitions_ClassesEntry {
return { key: 0, value: undefined };
}
export const SkillDefinitions_ClassesEntry: MessageFns<SkillDefinitions_ClassesEntry> = {
encode(message: SkillDefinitions_ClassesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.key !== undefined) {
if (message.key !== 0) {
writer.uint32(8).uint32(message.key);
}
if (message.value !== undefined) {
@@ -119,7 +125,7 @@ export const SkillDefinitions_ClassesEntry: MessageFns<SkillDefinitions_ClassesE
decode(input: BinaryReader | Uint8Array, length?: number): SkillDefinitions_ClassesEntry {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseSkillDefinitions_ClassesEntry();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -151,14 +157,14 @@ export const SkillDefinitions_ClassesEntry: MessageFns<SkillDefinitions_ClassesE
fromJSON(object: any): SkillDefinitions_ClassesEntry {
return {
key: globalThis.Number(assertSet("SkillDefinitions_ClassesEntry.key", object.key)),
value: Skill.fromJSON(assertSet("SkillDefinitions_ClassesEntry.value", object.value)),
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
value: isSet(object.value) ? Skill.fromJSON(object.value) : undefined,
};
},
toJSON(message: SkillDefinitions_ClassesEntry): unknown {
const obj: any = {};
if (message.key !== undefined) {
if (message.key !== 0) {
obj.key = Math.round(message.key);
}
if (message.value !== undefined) {
@@ -175,14 +181,12 @@ export const SkillDefinitions_ClassesEntry: MessageFns<SkillDefinitions_ClassesE
): SkillDefinitions_ClassesEntry {
const message = createBaseSkillDefinitions_ClassesEntry();
message.key = object.key ?? 0;
message.value = (object.value !== undefined && object.value !== null)
? Skill.fromPartial(object.value)
: createBaseSkill();
message.value = (object.value !== undefined && object.value !== null) ? Skill.fromPartial(object.value) : undefined;
return message;
},
};
export function createBaseSkill(): Skill {
function createBaseSkill(): Skill {
return { skills: [] };
}
@@ -196,7 +200,7 @@ export const Skill: MessageFns<Skill> = {
decode(input: BinaryReader | Uint8Array, length?: number): Skill {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseSkill();
while (reader.pos < end) {
const tag = reader.uint32();
@@ -263,14 +267,6 @@ function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
function assertSet<T>(field: string, value: T | undefined): T {
if (!isSet(value)) {
throw new TypeError(`Required field ${field} is not set`);
}
return value as T;
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter;
decode(input: BinaryReader | Uint8Array, length?: number): T;
+134 -124
View File
@@ -2,48 +2,58 @@ syntax = "proto2";
package blitzkit;
import "packages/core/src/protos/i18n.proto";
import "i18n.proto";
message TankDefinitions {
map<uint32, TankDefinition> tanks = 1;
}
message TankDefinition {
required uint32 id = 1;
required string slug = 2;
map<uint32, uint32> roles = 3;
required bool fixed_camouflage = 5;
repeated int32 camouflages = 6;
repeated int32 ancestors = 7;
repeated int32 successors = 8;
repeated Crew crew = 9;
required uint32 health = 10;
required string nation = 11;
required I18nString name = 12;
required TankType type = 13;
required uint32 max_consumables = 14;
required uint32 max_provisions = 15;
required uint32 tier = 16;
required TankClass class = 17;
required bool testing = 18;
required bool deprecated = 19;
repeated TurretDefinition turrets = 20;
repeated EngineDefinition engines = 21;
repeated TrackDefinition tracks = 22;
required TankPrice price = 23;
optional ResearchCost research_cost = 24;
required float speed_forwards = 25;
required float speed_backwards = 26;
required float camouflage_still = 27;
required float camouflage_moving = 28;
required float camouflage_onFire = 29;
required string equipment_preset = 30;
required uint32 weight = 31;
required uint32 id = 1;
required string slug = 2;
map<uint32, uint32> roles = 3;
required bool fixed_camouflage = 5;
repeated int32 camouflages = 6;
repeated int32 ancestors = 7;
repeated int32 successors = 8;
repeated Crew crew = 9;
required uint32 health = 10;
required string nation = 11;
required I18nString name = 12;
required TankType type = 13;
required uint32 max_consumables = 14;
required uint32 max_provisions = 15;
required uint32 tier = 16;
required TankClass class = 17;
required bool testing = 18;
required bool deprecated = 19;
repeated TurretDefinition turrets = 20;
repeated EngineDefinition engines = 21;
repeated TrackDefinition tracks = 22;
required TankPrice price = 23;
optional ResearchCost research_cost = 24;
required float speed_forwards = 25;
required float speed_backwards = 26;
required float camouflage_still = 27;
required float camouflage_moving = 28;
required float camouflage_on_fire = 29;
required string equipment_preset = 30;
required uint32 weight = 31;
required string dev_name = 32;
optional Equalizer equalizer = 33;
}
message Equalizer {
required float health = 1;
required float penetration = 2;
required float module_health = 3;
required float damage = 4;
required float armor = 5;
}
message ResearchCost {
oneof research_cost_type {
uint32 xp = 1;
uint32 xp = 1;
ResearchCostSeasonalTokens seasonal_tokens = 2;
}
}
@@ -55,77 +65,77 @@ message ResearchCostSeasonalTokens {
enum TankPriceType {
TANK_PRICE_TYPE_CREDITS = 0;
TANK_PRICE_TYPE_GOLD = 1;
TANK_PRICE_TYPE_GOLD = 1;
}
message TankPrice {
required TankPriceType type = 1;
required uint32 value = 2;
required TankPriceType type = 1;
required uint32 value = 2;
}
message TrackDefinition {
required uint32 id = 1;
required uint32 tier = 2;
required I18nString name = 3;
required uint32 weight = 4;
required float traverse_speed = 5;
optional ResearchCost research_cost = 6;
required float dispersion_move = 7;
required float dispersion_traverse = 8;
required float resistance_hard = 9;
required float resistance_medium = 10;
required float resistance_soft = 11;
repeated Unlock unlocks = 12;
required uint32 id = 1;
required uint32 tier = 2;
required I18nString name = 3;
required uint32 weight = 4;
required float traverse_speed = 5;
optional ResearchCost research_cost = 6;
required float dispersion_move = 7;
required float dispersion_traverse = 8;
required float resistance_hard = 9;
required float resistance_medium = 10;
required float resistance_soft = 11;
repeated Unlock unlocks = 12;
}
message EngineDefinition {
required uint32 id = 1;
required I18nString name = 2;
required uint32 id = 1;
required I18nString name = 2;
optional ResearchCost research_cost = 3;
required uint32 tier = 4;
required float fire_chance = 5;
required uint32 power = 6;
required uint32 weight = 7;
repeated Unlock unlocks = 8;
required uint32 tier = 4;
required float fire_chance = 5;
required uint32 power = 6;
required uint32 weight = 7;
repeated Unlock unlocks = 8;
}
message TurretDefinition {
required uint32 id = 1;
required uint32 health = 2;
required uint32 view_range = 3;
required float traverse_speed = 4;
optional ResearchCost research_cost = 5;
required I18nString name = 6;
required uint32 tier = 7;
required uint32 weight = 8;
repeated GunDefinition guns = 9;
repeated Unlock unlocks = 10;
required uint32 id = 1;
required uint32 health = 2;
required uint32 view_range = 3;
required float traverse_speed = 4;
optional ResearchCost research_cost = 5;
required I18nString name = 6;
required uint32 tier = 7;
required uint32 weight = 8;
repeated GunDefinition guns = 9;
repeated Unlock unlocks = 10;
}
message GunDefinition {
oneof gun_type {
GunDefinitionRegular regular = 1;
GunDefinitionAutoLoader auto_loader = 2;
GunDefinitionRegular regular = 1;
GunDefinitionAutoLoader auto_loader = 2;
GunDefinitionAutoReloader auto_reloader = 3;
}
required uint32 id = 4;
required float rotation_speed = 5;
optional ResearchCost research_cost = 6;
required uint32 weight = 7;
required I18nString name = 8;
required uint32 tier = 9;
repeated ShellDefinition shells = 10;
required float camouflage_loss = 11;
required float aim_time = 12;
required float dispersion_base = 13;
required float dispersion_traverse = 14;
required float dispersion_shot = 15;
required float dispersion_damaged = 16;
repeated Unlock unlocks = 17;
required uint32 shell_capacity = 18;
optional AssaultRanges assault_ranges = 19;
optional Burst burst = 20;
required uint32 id = 4;
required float rotation_speed = 5;
optional ResearchCost research_cost = 6;
required uint32 weight = 7;
required I18nString name = 8;
required uint32 tier = 9;
repeated ShellDefinition shells = 10;
required float camouflage_loss = 11;
required float aim_time = 12;
required float dispersion_base = 13;
required float dispersion_traverse = 14;
required float dispersion_shot = 15;
required float dispersion_damaged = 16;
repeated Unlock unlocks = 17;
required uint32 shell_capacity = 18;
optional AssaultRanges assault_ranges = 19;
optional Burst burst = 20;
}
message GunDefinitionRegular {
@@ -134,101 +144,101 @@ message GunDefinitionRegular {
message GunDefinitionAutoLoader {
required float clip_reload = 1;
required float intra_clip = 2;
required float intra_clip = 2;
required float shell_count = 3;
}
message Burst {
required uint32 count = 1;
required float interval = 2;
required uint32 count = 1;
required float interval = 2;
}
message GunDefinitionAutoReloader {
repeated float shell_reloads = 1;
required float intra_clip = 2;
required float shell_count = 3;
required float intra_clip = 2;
required float shell_count = 3;
}
message AssaultRanges {
repeated AssaultRange ranges = 1;
repeated ShellType types = 2;
repeated ShellType types = 2;
}
message AssaultRange {
required float distance = 1;
required float factor = 2;
required float factor = 2;
}
message ShellDefinition {
required uint32 id = 1;
required I18nString name = 2;
required uint32 velocity = 3;
required uint32 armor_damage = 4;
required uint32 module_damage = 5;
required float caliber = 6;
required string icon = 7;
required ShellPenetration penetration = 8;
required ShellType type = 9;
optional float normalization = 10;
optional float ricochet = 11;
optional float explosion_radius = 12;
required uint32 range = 13;
required uint32 id = 1;
required I18nString name = 2;
required uint32 velocity = 3;
required uint32 armor_damage = 4;
required uint32 module_damage = 5;
required float caliber = 6;
required string icon = 7;
required ShellPenetration penetration = 8;
required ShellType type = 9;
optional float normalization = 10;
optional float ricochet = 11;
optional float explosion_radius = 12;
required uint32 range = 13;
}
enum ShellType {
SHELL_TYPE_AP = 0;
SHELL_TYPE_AP = 0;
SHELL_TYPE_APCR = 1;
SHELL_TYPE_HEAT = 2;
SHELL_TYPE_HE = 3;
SHELL_TYPE_HE = 3;
}
message ShellPenetration {
required float near = 1;
required float far = 2;
required float far = 2;
}
message Unlock {
required int32 id = 1;
required int32 id = 1;
required ModuleType type = 2;
required UnlockCost cost = 3;
}
message UnlockCost {
required string type = 1;
required int32 value = 2;
required string type = 1;
required int32 value = 2;
}
enum ModuleType {
MODULE_TYPE_VEHICLE = 0;
MODULE_TYPE_ENGINE = 1;
MODULE_TYPE_TRACKS = 2;
MODULE_TYPE_TURRET = 3;
MODULE_TYPE_GUN = 4;
MODULE_TYPE_ENGINE = 1;
MODULE_TYPE_TRACKS = 2;
MODULE_TYPE_TURRET = 3;
MODULE_TYPE_GUN = 4;
}
enum TankClass {
TANK_CLASS_LIGHT = 0;
TANK_CLASS_MEDIUM = 1;
TANK_CLASS_HEAVY = 2;
TANK_CLASS_LIGHT = 0;
TANK_CLASS_MEDIUM = 1;
TANK_CLASS_HEAVY = 2;
TANK_CLASS_TANK_DESTROYER = 3;
}
enum TankType {
TANK_TYPE_RESEARCHABLE = 0;
TANK_TYPE_PREMIUM = 1;
TANK_TYPE_COLLECTOR = 2;
TANK_TYPE_PREMIUM = 1;
TANK_TYPE_COLLECTOR = 2;
}
message Crew {
required CrewType type = 1;
required uint32 count = 2;
required CrewType type = 1;
required uint32 count = 2;
repeated CrewType substitute = 3;
}
enum CrewType {
CREW_TYPE_COMMANDER = 0;
CREW_TYPE_RADIOMAN = 1;
CREW_TYPE_GUNNER = 2;
CREW_TYPE_DRIVER = 3;
CREW_TYPE_LOADER = 4;
CREW_TYPE_RADIOMAN = 1;
CREW_TYPE_GUNNER = 2;
CREW_TYPE_DRIVER = 3;
CREW_TYPE_LOADER = 4;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,3 @@
export function bufferToBigInt(buffer: ArrayBuffer) {
return new DataView(buffer).getBigUint64(0, true);
}
+2
View File
@@ -1,4 +1,5 @@
export * from './buffer';
export * from './bufferToBigInt';
export * from './dds';
export * from './dids';
export * from './pvr';
@@ -7,3 +8,4 @@ export * from './sc2';
export * from './scg';
export * from './scpg';
export * from './windows';
+12 -12
View File
@@ -1,5 +1,5 @@
import { clamp, isEqual, times } from 'lodash-es';
import { ReadStream } from './buffer';
import { clamp, isEqual, times } from "lodash-es";
import { ReadStream } from "./buffer";
export enum PvrFlags {
NoFlag = 0,
@@ -96,7 +96,7 @@ export class PvrReadStream extends ReadStream {
const header = this.header();
this.metadata();
if (typeof header.pixelFormat === 'number') {
if (typeof header.pixelFormat === "number") {
switch (header.pixelFormat) {
default:
throw new TypeError(
@@ -142,12 +142,12 @@ export class PvrReadStream extends ReadStream {
times(pixelCount, (index) => {
const buffer = this.consumeUint8Array(2);
const bufferIndex = index * 4;
const bufferIndex = index * 3;
const r = ((buffer[1] & 0b11111000) >>> 3) / 31;
const g =
((buffer[1] & 0b111) << 3) |
(((buffer[0] & 0b11100000) >>> 5) / 31);
const b = buffer[0] & 0b11111;
(((buffer[1] & 0b111) << 3) | ((buffer[0] & 0b11100000) >>> 5)) /
63;
const b = (buffer[0] & 0b11111) / 31;
data[bufferIndex] = Math.round(clamp(r * 255, 0, 255));
data[bufferIndex + 1] = Math.round(clamp(g * 255, 0, 255));
@@ -186,7 +186,7 @@ export class PvrReadStream extends ReadStream {
metadataSize: this.uint32(),
};
if (header.version !== 'PVR\x03') throw new TypeError('Endian mismatch');
if (header.version !== "PVR\x03") throw new TypeError("Endian mismatch");
return header;
}
@@ -205,19 +205,19 @@ export class PvrReadStream extends ReadStream {
resolveBitRatePixelFormat(
pixelFormat: Exclude<ReturnType<typeof this.pixelFormat>, number>,
) {
if (pixelFormat.order === 'rgba') {
if (pixelFormat.order === "rgba") {
if (isEqual(pixelFormat.bitRates, [4, 4, 4, 4])) {
return ResolvedBitRatePixelFormat.R4G4B4A4;
} else
throw new TypeError(
`Unhandled rgba bit rate ${pixelFormat.bitRates.join(', ')}`,
`Unhandled rgba bit rate ${pixelFormat.bitRates.join(", ")}`,
);
} else if (pixelFormat.order === 'rgb\0') {
} else if (pixelFormat.order === "rgb\0") {
if (isEqual(pixelFormat.bitRates, [5, 6, 5, 0])) {
return ResolvedBitRatePixelFormat.R5G6B5A0;
} else
throw new TypeError(
`Unhandled rgb bit rate ${pixelFormat.bitRates.join(', ')}`,
`Unhandled rgb bit rate ${pixelFormat.bitRates.join(", ")}`,
);
} else {
throw new TypeError(`Unhandled pixel order ${pixelFormat.order}`);
+4 -1
View File
@@ -15,6 +15,9 @@ type DataNode = {
qualityGroup?: string;
fxName?: string;
textures?: Textures;
customCullMode?: number;
enabledPresets?: EnabledPresets;
properties?: Properties;
} & (
| ({
configCount: number;
@@ -24,7 +27,7 @@ type DataNode = {
}
);
interface ConfigArchive {
export interface ConfigArchive {
configName: string;
fxName: string;
properties: Properties;
+12 -3
View File
@@ -357,6 +357,8 @@
},
"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": {
"name": "replay",
"description": "Display replay results",
@@ -1081,6 +1083,7 @@
"tier": "Tier",
"type": "Type",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Purchase price",
"restoration": "Restoration price",
"sale": "Sale price",
@@ -1106,6 +1109,11 @@
"configuration": {
"title": "Configuration",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Modules",
"stock": "Stock",
@@ -1139,8 +1147,8 @@
"title": "Characteristics",
"compare": {
"label": "Compare",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "All tanks"
},
"values": {
@@ -1283,7 +1291,8 @@
},
"skills": {
"clear": "Clear",
"maximize": "Maximize"
"maximize": "Maximize",
"equalize": "Equalize"
},
"modules": {
"stock": "Stock",
+15 -469
View File
@@ -37,10 +37,11 @@
"d_1": "Ayer"
},
"branches": {
"local": "DEV",
"dev": "Beta",
"opentest": "Prueba Abierta",
"preview": "Avance"
"beta": "Beta",
"development": "Development",
"opentest": "Prueba abierta",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Ingles",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Tiempo total de batalla"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
"player_not_linked": "# Usa `/vincular` para empezar\n¡No sé quién eres, pero puedes decírmelo hoy!",
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
"no_tank_stats": "# No hay estadísticas de tanque disponibles\nEste jugador no tiene estadísticas disponibles. Este podría no ser el jugador que estás buscando.",
"get_help": "Servidor de ayuda de Discord",
"uncaught_error": "# ¡Blitzkrieg sufrió un error!\nLo sentimos mucho. Siéntete libre de [unirte al servidor oficial de Discord](https://discord.gg/nDt7AjGJQH) para obtener ayuda.",
"preview": "# Este comando es una vista previa\n\nSolo puedes acceder a este comando en [el servidor oficial de Discord](https://discord.gg/nDt7AjGJQH). Generalmente este comando estará disponible pronto.",
"query_too_small": "# Tu búsqueda es demasiado corta\nDebe ser por lo menos de 3 caracteres de largo.",
"query_too_long": "# Tu búsqueda es demasiado larga\nDebe ser como mucho de 100 caracteres de largo."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Muy Malo",
"bad": "Malo",
"below_average": "Debajo del Promedio",
"average": "Promedio",
"above_average": "Superior al Promedio",
"good": "Bueno",
"very_good": "Muy Bueno",
"great": "Excelente",
"unicum": "Unicum",
"super_unicum": "Super Unicum"
}
},
"subcommands": {
"today": {
"name": "Hoy",
"description": "Hoy"
},
"30": {
"name": "30",
"description": "30 días"
},
"60": {
"name": "60",
"description": "60 días"
},
"90": {
"name": "90",
"description": "90 días"
},
"career": {
"name": "carrera",
"description": "Carrera"
},
"custom": {
"name": "personalizado",
"description": "Rango personalizado",
"options": {
"start": {
"name": "comenzar",
"description": "Comenzar en cantidad de días pasados desde hoy"
},
"end": {
"name": "fin",
"description": "Terminar en cantidad de días pasados desde hoy"
}
}
}
},
"options": {
"clan": {
"name": "clan",
"description": "El nombre o etiqueta del clan"
},
"tank": {
"name": "tanque",
"description": "El tanque al cual conseguirle estadísticas"
},
"username": {
"name": "nombre de usuario",
"description": "El nombre de usuario de Blitz"
},
"filters": {
"nation": {
"name": "nación",
"description": "Nación"
},
"class": {
"name": "clase",
"description": "Clase"
},
"type": {
"name": "tipo",
"description": "Tipo"
}
},
"region": {
"name": "región",
"description": "Región"
},
"tier": {
"name": "tier",
"description": "Nivel",
"choices": {
"tier": "Tier {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Carrera",
"today": "Hoy",
"days": "{days} days",
"custom": "{day_1} - {day_2} days"
},
"filters": {
"none": "Sin filtros",
"tier": "Tier {tier}"
},
"no_data": {
"battles_in_period": "No hay batallas jugadas en este período",
"battles_in_season": "No hay batallas jugadas en esta temporada",
"players_in_period": "No hay jugadores en este período",
"tanks_found": "No se encontraron tanques"
},
"buttons": {
"refresh": "Actualizar"
},
"hero_stats": {
"battles": "Batallas",
"winrate": "Tasa de victorias",
"damage": "Daño",
"damage_ratio": "Relación de daño",
"tier": "Nivel",
"survival": "Supervivencia",
"accuracy": "Precisión",
"kills": "Bajas"
}
},
"commands": {
"replay": {
"name": "repetición",
"description": "Mostrar resultados de la repetición"
},
"research": {
"name": "desarollar",
"description": "Enumera los gastos por investigar una línea",
"options": {
"target_tank": {
"name": "tanque objetivo",
"description": "El último tanque a investigar en la línea"
},
"starting_tank": {
"name": "tanque de inicio",
"description": "El tanque inicial en la línea (se deduce automáticamente si no se proporciona)"
}
},
"body": {
"subtitle": "Investigar",
"total": "Total",
"research": "Research: {cost}",
"upgrades": "Upgrades: {cost}",
"purchase": "Purchase: {cost}",
"equipment": "Equipment: {cost}",
"estimation": "# ¡Esto es una estimación!\n\nEsta lista podría incluir tanques ya investigados debido a la información errónea que proporciona Wargaming. Si puedes, prueba proporcionando un `tanque-inicial` de la línea al usar el comando."
},
"errors": {
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
}
},
"about": {
"name": "acerca",
"description": "Toda la información que necesitas sobre el bot",
"subcommands": {
"commands": {
"name": "comandos",
"description": "Lista de todos los comandos y sus descripciones",
"body": "# Comandos\n\nBlitzKit ofrece los siguientes comandos:\n\n"
},
"embeds": {
"name": "embeds",
"description": "Cómo funcionan los embeds"
},
"introduction": {
"name": "introducción",
"description": "Sobre el bot"
},
"invite": {
"name": "invitar",
"description": "Cómo invitar al bot"
},
"timezones": {
"name": "zonas horarias",
"description": "Cómo Blitzkrieg infiere y utiliza tu zona horaria"
},
"credits": {
"name": "créditos",
"description": "Personas que han ayudado a BlitzKit"
}
}
},
"breakdown": {
"name": "resumen",
"description": "Resumen de un período por tanques jugados",
"body": {
"total": "Total",
"battles": "Batallas",
"wn8": "WN8",
"winrate": "Tasa de victorias",
"damage": "Daño",
"unknown_tank": "Unknown tank {id}"
}
},
"debug": {
"name": "depurar",
"description": "Muestra más información sobre el bot",
"body": {
"title": "# Depuración\n\n",
"version": "Versión",
"shard": {
"label": "Fragmentar",
"default": "predeterminado"
},
"uptime": "Tiempo en línea"
}
},
"evolution": {
"name": "evolución",
"description": "Evolución de estadísticas",
"groups": {
"player": {
"name": "jugador",
"description": "Estadísticas del jugador"
},
"tank": {
"name": "tanque",
"description": "Estadísticas del tanque"
}
}
},
"inactive": {
"name": "inactivo",
"description": "Enumera a todos los jugadores inactivos en un clan por encima de un umbral",
"options": {
"threshold": {
"name": "umbral",
"description": "The number of days inactive (default: {days} days)"
}
},
"body": {
"subtitle": "Inactive for {days}+ days",
"listing": "{days} days"
}
},
"full_stats": {
"name": "estadísticas completas",
"description": "Estadísticas completas del juego",
"body": {
"cards": {
"games": {
"title": "Partidas",
"winrate": "Tasa de victorias",
"battles": "Batallas",
"wins_losses": "Victorias / derrotas"
},
"efficiency": {
"title": "Eficiencia",
"wn8": "WN8",
"survival": "Supervivencia",
"accuracy": "Precisión"
},
"lethality": {
"title": "Letalidad",
"average_damage": "Daño promedio",
"damage_per_tier": "Daño por nivel",
"damage_ratio": "Relación de daño",
"average_kills": "Promedio de bajas"
},
"miscellaneous": {
"title": "Misceláneo",
"average_tier": "Nivel promedio",
"average_spots": "Promedio de detecciones",
"average_xp": "Promedio de XP",
"kills_to_death_ratio": "Relación bajas-muertes"
}
}
}
},
"link": {
"name": "vincular",
"description": "Vincula tu cuenta de Blitz y Discord",
"body": {
"accounts_linked": "Cuentas vinculadas",
"no_role_permissions": {
"title": "{name} failed to verify",
"description": "No tengo permiso para administrar roles."
}
},
"embed": {
"title": "¿Cuenta incorrecta?",
"description": "Usa el comando de nuevo y selecciona un usuario de los resultados de búsqueda."
}
},
"search_clans": {
"name": "buscar clanes",
"description": "Buscar clanes",
"options": {
"limit": {
"name": "límite",
"description": "The max number of clan results (default: {limit})"
}
},
"body": {
"title": "Clan search for {search} in region {region}",
"no_results": "No se encontraron clanes"
}
},
"search_players": {
"name": "buscar jugadores",
"description": "Buscar jugadores",
"options": {
"limit": {
"name": "límite",
"description": "The max number of player results (default: {limit})"
}
},
"body": {
"title": "Player search for {search} in region {region}",
"no_results": "No se encontraron jugadores"
}
},
"rating_leaderboard": {
"name": "tabla de clasificación",
"description": "Estadísticas de batallas de clasificatoria",
"subcommands": {
"neighbors": {
"name": "vecinos",
"description": "Jugadores vecinos en la tabla de posiciones"
},
"league": {
"name": "liga",
"description": "Mejores jugadores de una liga"
}
},
"options": {
"limit": {
"name": "limite",
"description": "How many neighbors to display (default: {count})"
},
"season": {
"name": "temporada",
"description": "Número de temporada (predeterminado: actual)",
"choices": {
"current": "{season} (current)"
}
},
"league": {
"name": "liga",
"description": "La liga a mostrar"
}
},
"body": {
"top_players": "Top {count} players",
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
"no_ongoing_season": "# No hay temporada en curso\n\nActualmente no hay ninguna temporada de clasificatoria.",
"deleted_player": "Deleted {id}",
"neighbors": "Vecinos de clasificatoria",
"more": "+ {count} more"
}
},
"today": {
"name": "hoy",
"description": "Tanques jugados hoy y estadísticas"
},
"stats": {
"name": "estadísticas",
"description": "Estadísticas rápidas para un período"
},
"owned_tanks": {
"name": "tanques en propiedad",
"description": "Muestra todos los tanques propios en un nivel",
"body": {
"title": "# {name}'s owned tier {tier} tanks\n\n"
}
},
"permissions": {
"name": "permisos",
"description": "Comprueba si el bot tiene los permisos requeridos para funcionar",
"body": {
"title": "# Permissions\n\n{body}",
"view_channels": "Ver canales: necesario para encontrar el mensaje en el cual el botón \"actualizar\" fue usado",
"read_message_history": "Leer historial de mensajes: necesario para encontrar el mensaje a actualizar",
"attach_files": "Adjuntar archivos: necesario para añadir imágenes a los comandos basados en estas",
"external_emojis": "Emoticonos externos: necesario para añadir emoticonos de banderas nacionales y clases de tanque"
}
},
"ping": {
"name": "ping",
"description": "Comprueba si el bot está vivo.",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time}ms"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Hacerle un ping a BlitzKit"
},
"wotb": {
"name": "wotb",
"description": "Hacerle un ping a World of Tanks Blitz"
}
}
},
"player_info": {
"name": "info del jugador",
"description": "Información básica sobre un jugador",
"body": {
"title": "{name}'s information",
"nickname": "Apodo",
"battles": "Batallas",
"winrate": "Tasa de victorias",
"account_id": "ID de cuenta",
"created": "Creado",
"last_battle": "Última batalla"
}
},
"rating": {
"name": "clasificatoria",
"description": "Estadísticas de clasificatoria del jugador",
"subcommands": {
"today": {
"name": "hoy",
"description": "Estadísticas de clasificatoria de hoy"
},
"season": {
"name": "temporada",
"description": "Estadísticas de clasificatoria de esta temporada"
}
},
"body": {
"subtitle": {
"today": "Estadísticas de clasificatoria de hoy",
"season": "Estadísticas de clasificatoria de esta temporada"
}
},
"errors": {
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
"unrecorded_stats": "# Estadísticas no disponibles actualmente\n\nWargaming podría estar sufriendo una caída del servidor. Si hay alguna temporada en curso, las estadísticas deberían estar disponibles en 24 horas."
}
}
}
},
"website": {
"redirect": {
"title": "301: moved permanently",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "NEW",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
@@ -953,6 +492,7 @@
"tier": "Nivel",
"type": "Tipo",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Precio de compra",
"restoration": "Precio de restauración",
"sale": "Precio de venta",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Módulos",
"stock": "Base",
@@ -1005,8 +550,8 @@
"title": "Características",
"compare": {
"label": "Comparar con",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "Todos los tanques"
},
"values": {
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Limpiar",
"maximize": "Maximizar"
"maximize": "Maximizar",
"equalize": "Equalize"
},
"modules": {
"stock": "Base",
+15 -469
View File
@@ -37,10 +37,11 @@
"d_1": "Hier"
},
"branches": {
"local": "dev",
"dev": "beta",
"opentest": "test ouvert",
"preview": "aperçu"
"beta": "Beta",
"development": "Development",
"opentest": "OpenTest",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Anglais",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Total de temps de bataille"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Impossible de trouver le clan\nImpossible de trouver «{search} ». Essayez de sélectionner un clan dans le résultat de la recherche.",
"player_not_found": "# Impossible de trouver l'utilisateur\nJe n'ai pas pu trouver l'utilisateur \"{search}\". Essayez de choisir un utilisateur dans le résultat de la recherche, en tapant un nom d'utilisateur valide, ou en utilisant la commande `/link`.",
"player_not_linked": "# Utilisez `/link` pour commencer\nJe ne sais pas qui vous êtes, mais vous pouvez me le dire aujourd'hui !",
"tank_name_not_found": "# Char introuvable\nImpossible de trouver le char sous le nom \"{search}\".",
"tank_id_not_found": "# Char introuvable\nImpossible de trouver le char avec l'ID \"{search}\". Essayez de taper le nom du char au lieu d'un nombre.",
"no_tank_stats": "# Aucune statistique de tank disponible\nCe joueur n'a pas de statistiques disponibles. Ce n'est peut-être pas le joueur que vous cherchez.",
"get_help": "Aidez le serveur Discord",
"uncaught_error": "# Blitzkit a rencontré une erreur !\nNous sommes désolés de cela. N'hésitez pas à [rejoindre le serveur officiel Discord](https://discord.gg/nDt7AjGJQH) pour obtenir de l'aide.",
"preview": "# Cette commande est en aperçu\n\nVous ne pouvez accéder à cette commande que dans [le serveur officiel Discord](https://discord.gg/nDt7AjGJQH). La commande sera généralement disponible sous peu.",
"query_too_small": "# Votre recherche est trop courte\nVotre recherche doit comporter au moins 3 caractères.",
"query_too_long": "# Votre recherche est trop longue\nVotre recherche doit comporter au maximum 100 caractères."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Très nul",
"bad": "Nul",
"below_average": "En-dessous de la moyenne",
"average": "Moyenne",
"above_average": "Au-dessus de la moyenne",
"good": "Bien",
"very_good": "Très bien",
"great": "Super",
"unicum": "Unique",
"super_unicum": "Super unique"
}
},
"subcommands": {
"today": {
"name": "aujourd'hui",
"description": "Aujourd'hui"
},
"30": {
"name": "30",
"description": "30 jours"
},
"60": {
"name": "60",
"description": "60 jours"
},
"90": {
"name": "90",
"description": "90 jours"
},
"career": {
"name": "carrière",
"description": "Carrière"
},
"custom": {
"name": "personnaliser",
"description": "Période spécifique",
"options": {
"start": {
"name": "début",
"description": "Commencer il y a un nombre de jours à partir d'aujourd'hui"
},
"end": {
"name": "fin",
"description": "Fin en nombre de jours à partir d'aujourd'hui"
}
}
}
},
"options": {
"clan": {
"name": "clan",
"description": "Le nom ou le tag du clan"
},
"tank": {
"name": "char",
"description": "Le char pour obtenir des statistiques pour"
},
"username": {
"name": "nom d'utilisateur",
"description": "Le nom d'utilisateur Blitz du joueur"
},
"filters": {
"nation": {
"name": "pays",
"description": "Pays"
},
"class": {
"name": "classe",
"description": "Classe"
},
"type": {
"name": "type",
"description": "Type"
}
},
"region": {
"name": "région",
"description": "Région"
},
"tier": {
"name": "rang",
"description": "Rang",
"choices": {
"tier": "Rang {tier_}1 - {tier_}2"
}
}
},
"periods": {
"career": "Carrière",
"today": "Aujourd'hui",
"days": "{days} jours",
"custom": "{day_1} - {day_2} jours"
},
"filters": {
"none": "Aucun filtre",
"tier": "Rang {tier}"
},
"no_data": {
"battles_in_period": "",
"battles_in_season": "Aucune bataille jouée dans cette saison",
"players_in_period": "Aucun joueur pendant cette période",
"tanks_found": "Aucun char de trouver"
},
"buttons": {
"refresh": "Actualiser"
},
"hero_stats": {
"battles": "Batailles",
"winrate": "Taux de victoires",
"damage": "Dégâts",
"damage_ratio": "Rapport de dégâts",
"tier": "Rang",
"survival": "Survie",
"accuracy": "Précision",
"kills": "Tués"
}
},
"commands": {
"replay": {
"name": "rejouer",
"description": "Afficher les résultats de la relecture"
},
"research": {
"name": "recherche",
"description": "Liste des dépenses liées à la recherche d'une ligne",
"options": {
"target_tank": {
"name": "char cible",
"description": "Le dernier char à rechercher dans la ligne"
},
"starting_tank": {
"name": "Char de départ",
"description": ""
}
},
"body": {
"subtitle": "Recherche",
"total": "Total",
"research": "Recherche : {cost}",
"upgrades": "Améliorations : {cost}",
"purchase": "Achat : {cost}",
"equipment": "Équipement : {cost}",
"estimation": "# Ceci est une estimation !\n\nCette liste peut inclure des chars déjà recherchés en raison de l'information inexacte fournie par Wargaming. Essayez de fournir un `char de départ` depuis la ligne lorsque vous utilisez la commande si vous le pouvez."
},
"errors": {
"non_tech_tree": "# {tank} n'est pas dans l'arbre technologique\n\nVous ne pouvez pas rechercher un char premium/de collection.",
"tier_1": "# {tank} est un char de rang I\n\nLe char de rang 1 sont déverrouillé gratuitement pour tous les joueurs.",
"already_researched": "# {tank} est déjà recherché\n\nEssayez de fournir un `char de départ` en utilisant la commande pour voir la progression d'une lignée.",
"start_end_equal": "# {tank} a été fourni deux fois\n\nAssurez-vous que `starting-tank` et `target-tank` sont différents.",
"tanks_not_on_line": "{tank_}1 et {tank_}2 ne sont pas sur la même ligne \n\nAssurez-vous que `starting-tank` et `target-tank` sont sur la même ligne d'arbre technologique.",
"unordered": "# {tank_1} niveau supérieur à {tank_2}\n\nAssurez-vous de fournir {tank_2} comme le `starting-tank` à la place car c'est le char de niveau inférieur."
}
},
"about": {
"name": "à propos",
"description": "Toutes les informations dont vous avez besoin sur le bot",
"subcommands": {
"commands": {
"name": "commandes",
"description": "Liste de toutes les commandes et leurs descriptions",
"body": "# Commandes\n\nBlitzKit offre les commandes suivantes :\n\n"
},
"embeds": {
"name": "intègre",
"description": "Comment fonctionnent les intégrations"
},
"introduction": {
"name": "introduction",
"description": "À propos du bot"
},
"invite": {
"name": "inviter",
"description": "Comment inviter le bot"
},
"timezones": {
"name": "fuseau horaire",
"description": "Comment BlitzKit déduit et utilise votre fuseau horaire"
},
"credits": {
"name": "crédits",
"description": "Personnes qui ont aidé BlitzKit"
}
}
},
"breakdown": {
"name": "décomposition",
"description": "Répartition d'une période par chars joués",
"body": {
"total": "Total",
"battles": "Batailles",
"wn8": "WN8",
"winrate": "Taux de victoires",
"damage": "Dégâts",
"unknown_tank": "Char {id} inconnu"
}
},
"debug": {
"name": "déboguer",
"description": "Déboguer les informations sur le bot",
"body": {
"title": "# Debog\n\n",
"version": "Version",
"shard": {
"label": "Fragment",
"default": "par défaut"
},
"uptime": "Temps de fonctionnement"
}
},
"evolution": {
"name": "évolution",
"description": "Évolution des statistiques",
"groups": {
"player": {
"name": "joueur",
"description": "Statistiques du joueur"
},
"tank": {
"name": "char",
"description": "Statistiques du char"
}
}
},
"inactive": {
"name": "inactif",
"description": "Liste tous les joueurs inactifs dans un clan au-dessus d'un seuil",
"options": {
"threshold": {
"name": "seuil",
"description": "Le nombre de jours inactifs (par défaut: {days} jours)"
}
},
"body": {
"subtitle": "Inactif depuis plus de {days} jours",
"listing": "{days} jours"
}
},
"full_stats": {
"name": "statistiques complètes",
"description": "Statistiques complètes en jeu",
"body": {
"cards": {
"games": {
"title": "Parties",
"winrate": "Taux de victoires",
"battles": "Batailles",
"wins_losses": "Victoires/Défaites"
},
"efficiency": {
"title": "Efficacité",
"wn8": "WN8",
"survival": "Survie",
"accuracy": "Précision"
},
"lethality": {
"title": "Létalité",
"average_damage": "Dégâts moyens",
"damage_per_tier": "Dégâts par tier",
"damage_ratio": "Rapport de dégâts",
"average_kills": "Destruction moyenne"
},
"miscellaneous": {
"title": "Divers",
"average_tier": "Tier moyen",
"average_spots": "Repérage moyen",
"average_xp": "Exp. Moyenne par bataille",
"kills_to_death_ratio": "Rapport tués/morts"
}
}
}
},
"link": {
"name": "lien",
"description": "Lier votre compte Blitz et Discord",
"body": {
"accounts_linked": "Comptes liés",
"no_role_permissions": {
"title": "La vérification de {name} a échouée",
"description": "Je n'ai pas l'autorisation de gérer les rôles."
}
},
"embed": {
"title": "Compte invalide ?",
"description": "Utilisez à nouveau la commande et sélectionnez un nom d'utilisateur à partir des résultats de recherche."
}
},
"search_clans": {
"name": "clans de recherche",
"description": "Rechercher des clans",
"options": {
"limit": {
"name": "limite",
"description": "Nombre maximum de résultats du clan (par défaut: {limit})"
}
},
"body": {
"title": "Recherche de clan {search} dans la région {region}",
"no_results": "Pas de clan trouvé"
}
},
"search_players": {
"name": "recherche de joueur",
"description": "Recherche des joueurs",
"options": {
"limit": {
"name": "limite",
"description": "Le nombre maximum de résultats de joueur (par défaut: {limit})"
}
},
"body": {
"title": "Recherche de {search} dans la région {region}",
"no_results": "Pas de joueur de trouvé"
}
},
"rating_leaderboard": {
"name": "Classement de côté",
"description": "Statistiques des batailles de cotés",
"subcommands": {
"neighbors": {
"name": "voisins",
"description": "Joueurs voisins dans le classement"
},
"league": {
"name": "ligue",
"description": "Meilleurs joueurs d'une ligue"
}
},
"options": {
"limit": {
"name": "limite",
"description": "Combien de voisins afficher (par défaut : {count})"
},
"season": {
"name": "saison",
"description": "Numéro de saison (défaut : courant)",
"choices": {
"current": "{season} (actuel)"
}
},
"league": {
"name": "ligue",
"description": "La ligue à afficher"
}
},
"body": {
"top_players": "Top {count} joueurs",
"no_participation": "# {player} n'a pas joué de cotées dans la saison {season}\n\nCe joueur n'a pas participé à cette saison ou n'a pas dépassé l'étalonnage.",
"no_ongoing_season": "Pas de saison en cours\n\nIl n'y a pas de saison de notation en cours actuellement.",
"deleted_player": "{id} supprimé",
"neighbors": "évaluer les voisins",
"more": "+ {count} plus"
}
},
"today": {
"name": "aujourd'hui",
"description": "Les chars et les statistiques joués aujourd'hui"
},
"stats": {
"name": "statistiques",
"description": "Statistiques rapides pour une période"
},
"owned_tanks": {
"name": "chars possédés",
"description": "Affiche tous les chars d'un niveau",
"body": {
"title": "# Les chars du palier {tier} possédés par {name}"
}
},
"permissions": {
"name": "permissions",
"description": "Vérifie si le bot a les permissions nécessaires pour fonctionner",
"body": {
"title": "# Permissions\n\n{body}",
"view_channels": "Afficher les canaux : nécessaire pour trouver le message sur lequel le bouton d'actualisation a été utilisé",
"read_message_history": "Lire l'historique des messages : nécessaire pour trouver le message à rafraîchir",
"attach_files": "Joindre des fichiers : nécessaire pour ajouter des images à des commandes basées sur l'image",
"external_emojis": "Émoticônes externes: nécessaire pour ajouter des drapeaux nationaux et des émojis de classe de char"
}
},
"ping": {
"name": "ping",
"description": "Vérifiez si le bot est en vie.",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time}ms"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Ping blitzkit"
},
"wotb": {
"name": "wotb",
"description": "Ping World of Tanks Blitz"
}
}
},
"player_info": {
"name": "info-joueur",
"description": "Informations de base sur un joueur",
"body": {
"title": "Informations de {name}",
"nickname": "Pseudo",
"battles": "Batailles",
"winrate": "Taux de victoires",
"account_id": "Account ID",
"created": "Créé",
"last_battle": "Dernière bataille"
}
},
"rating": {
"name": "côtée",
"description": "Statistiques des batailles cotées du joueur",
"subcommands": {
"today": {
"name": "aujourd'hui",
"description": "Statistiques des batailles cotées d'aujourd'hui"
},
"season": {
"name": "saison",
"description": "Statistiques des batailles cotées de cette saison"
}
},
"body": {
"subtitle": {
"today": "Statistiques de batailles cotées d'aujourd'hui",
"season": "Statistiques de batailles cotées cette saison"
}
},
"errors": {
"no_participation": "# {name} n’a pas joué en cotée\n\nCe joueur n’a pas participé au mode cotée cette saison.",
"unrecorded_stats": "# Statistiques actuellement indisponibles\n\nWargaming rencontre peut-être une interruption de service.\nSi une saison est en cours, les statistiques devraient être disponibles sous 24 heures."
}
}
}
},
"website": {
"redirect": {
"title": "301 : déplacé définitivement",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "NEW",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
@@ -953,6 +492,7 @@
"tier": "Rang",
"type": "Type",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Purchase price",
"restoration": "Restoration price",
"sale": "Sale price",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "Configuration",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Modules",
"stock": "Stock",
@@ -1005,8 +550,8 @@
"title": "Characteristics",
"compare": {
"label": "Compare against",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "All tanks"
},
"values": {
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Clear",
"maximize": "Maximize"
"maximize": "Maximize",
"equalize": "Equalize"
},
"modules": {
"stock": "Stock",
+15 -469
View File
@@ -37,10 +37,11 @@
"d_1": "昨日"
},
"branches": {
"local": "開発",
"dev": "ベータ版",
"opentest": "オープンテスト",
"preview": "プレビュー"
"beta": "Beta",
"development": "Development",
"opentest": "OpenTest",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "英語",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "総戦闘時間"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "",
"player_not_found": "# ユーザーが見つかりませんでした\nユーザー「{search}」が見つかりませんでした。検索結果からユーザーを選択するか、有効なユーザー名を入力するか、/link コマンドを使用してください。",
"player_not_linked": "# `/link`を使用して始めましょう\nはじめまして!あなたが誰か、私に教えてください。",
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
"tank_id_not_found": "# 車両が見つかりません\nID「{search}」の戦車が見つかりませんでした。数字ではなく戦車の名前を入力してみてください。",
"no_tank_stats": "# 利用可能な車輌統計がありません\nこのプレイヤーには利用可能な統計がありません。あなたが探しているプレイヤーではない可能性があります。",
"get_help": "Discordサーバーに参加する",
"uncaught_error": "# BlitzKitがエラーに遭遇しました!\n申し訳ありません。お気軽に[公式Discordサーバー](https://discord.gg/nDt7AjGJQH)にお問い合わせください。",
"preview": "このコマンドは現在[公式Discardサーバー](https://discord.gg/nDt7AjGJQH)でのみ利用可能です。間もなく全体で利用可能になります。",
"query_too_small": "# 単語が短すぎます\n検索には少なくとも3文字が含まれている必要があります。",
"query_too_long": "# 単語が長すぎます\n検索は最大で100文字までです。"
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Very bad",
"bad": "Bad",
"below_average": "Below average",
"average": "Average",
"above_average": "Above average",
"good": "Good",
"very_good": "Very good",
"great": "Great",
"unicum": "Unicum",
"super_unicum": "Super unicum"
}
},
"subcommands": {
"today": {
"name": "today",
"description": "Today"
},
"30": {
"name": "30",
"description": "30日"
},
"60": {
"name": "60",
"description": "60日"
},
"90": {
"name": "90",
"description": "90日"
},
"career": {
"name": "総合戦績",
"description": "Career"
},
"custom": {
"name": "カスタム",
"description": "Custom range",
"options": {
"start": {
"name": "開始",
"description": "Start in number of days ago from today"
},
"end": {
"name": "end",
"description": "End in number of days ago from today"
}
}
}
},
"options": {
"clan": {
"name": "クラン",
"description": "クラン名もしくはタグ"
},
"tank": {
"name": "車輌",
"description": "統計を得る車輌"
},
"username": {
"name": "ユーザー名",
"description": "プレイヤーのBlitzユーザー名"
},
"filters": {
"nation": {
"name": "国家",
"description": "国家"
},
"class": {
"name": "",
"description": "Class"
},
"type": {
"name": "type",
"description": "Type"
}
},
"region": {
"name": "地域",
"description": "地域"
},
"tier": {
"name": "tier",
"description": "Tier",
"choices": {
"tier": "Tier {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Career",
"today": "Today",
"days": "{days} days",
"custom": "{day_1} - {day_2} days"
},
"filters": {
"none": "フィルターなし",
"tier": "Tier {tier}"
},
"no_data": {
"battles_in_period": "No battles played in this period",
"battles_in_season": "No battles played in this season",
"players_in_period": "No players in this period",
"tanks_found": "No tanks found"
},
"buttons": {
"refresh": "Refresh"
},
"hero_stats": {
"battles": "戦闘数",
"winrate": "勝率",
"damage": "ダメージ",
"damage_ratio": "ダメージ率",
"tier": "Tier",
"survival": "生存",
"accuracy": "命中率",
"kills": "撃破"
}
},
"commands": {
"replay": {
"name": "replay",
"description": "Display replay results"
},
"research": {
"name": "研究",
"description": "Lists the expenses in researching a line",
"options": {
"target_tank": {
"name": "target-tank",
"description": "The final tank to research in the line"
},
"starting_tank": {
"name": "starting-tank",
"description": "The starting tank in the line (inferred automatically if not provided)"
}
},
"body": {
"subtitle": "Research",
"total": "トータル",
"research": "Research: {cost}",
"upgrades": "Upgrades: {cost}",
"purchase": "Purchase: {cost}",
"equipment": "Equipment: {cost}",
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
},
"errors": {
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
}
},
"about": {
"name": "about",
"description": "botについての情報の全て",
"subcommands": {
"commands": {
"name": "コマンド",
"description": "全コマンドのリストと説明",
"body": "# コマンド\nBlitzKitは以下のコマンドを提供します:"
},
"embeds": {
"name": "埋め込み",
"description": "埋め込みがどう機能するか"
},
"introduction": {
"name": "introduction",
"description": "botについて"
},
"invite": {
"name": "招待",
"description": "botを招待する方法"
},
"timezones": {
"name": "タイムゾーン",
"description": "How BlitzKit infers and uses your timezone"
},
"credits": {
"name": "クレジット",
"description": "BlitzKitを支援した人々"
}
}
},
"breakdown": {
"name": "breakdown",
"description": "A period's breakdown by tanks played",
"body": {
"total": "トータル",
"battles": "戦闘数",
"wn8": "WN8",
"winrate": "勝率",
"damage": "ダメージ",
"unknown_tank": "不明な車両{id}"
}
},
"debug": {
"name": "debug",
"description": "Debug information about the bot",
"body": {
"title": "# Debug\n\n",
"version": "Version",
"shard": {
"label": "Shard",
"default": "default"
},
"uptime": "Uptime"
}
},
"evolution": {
"name": "evolution",
"description": "Evolution of statistics",
"groups": {
"player": {
"name": "player",
"description": "Player statistics"
},
"tank": {
"name": "車輌",
"description": "Tank statistics"
}
}
},
"inactive": {
"name": "inactive",
"description": "Lists all inactive players in a clan above a threshold",
"options": {
"threshold": {
"name": "threshold",
"description": "The number of days inactive (default: {days} days)"
}
},
"body": {
"subtitle": "Inactive for {days}+ days",
"listing": "{days} days"
}
},
"full_stats": {
"name": "full-stats",
"description": "Full in-game statistics",
"body": {
"cards": {
"games": {
"title": "Games",
"winrate": "勝率",
"battles": "戦闘数",
"wins_losses": "Wins / losses"
},
"efficiency": {
"title": "Efficiency",
"wn8": "WN8",
"survival": "生存",
"accuracy": "精度"
},
"lethality": {
"title": "Lethality",
"average_damage": "Average damage",
"damage_per_tier": "Damage per tier",
"damage_ratio": "ダメージ比",
"average_kills": "Average kills"
},
"miscellaneous": {
"title": "Miscellaneous",
"average_tier": "Average tier",
"average_spots": "Average spots",
"average_xp": "Average XP",
"kills_to_death_ratio": "撃破/被撃破比"
}
}
}
},
"link": {
"name": "link",
"description": "Links your Blitz and Discord account",
"body": {
"accounts_linked": "Accounts linked",
"no_role_permissions": {
"title": "{name} failed to verify",
"description": "I don't have the permission to manage roles."
}
},
"embed": {
"title": "Incorrect account?",
"description": "Use the command again and select a username from the search results."
}
},
"search_clans": {
"name": "search-clans",
"description": "Search clans",
"options": {
"limit": {
"name": "limit",
"description": "The max number of clan results (default: {limit})"
}
},
"body": {
"title": "Clan search for {search} in region {region}",
"no_results": "No clans found"
}
},
"search_players": {
"name": "search-players",
"description": "Search players",
"options": {
"limit": {
"name": "limit",
"description": "The max number of player results (default: {limit})"
}
},
"body": {
"title": "Player search for {search} in region {region}",
"no_results": "No players found"
}
},
"rating_leaderboard": {
"name": "rating-leaderboard",
"description": "Rating battles statistics",
"subcommands": {
"neighbors": {
"name": "neighbors",
"description": "Neighboring players on the leaderboard"
},
"league": {
"name": "league",
"description": "Top players of a league"
}
},
"options": {
"limit": {
"name": "limit",
"description": "How many neighbors to display (default: {count})"
},
"season": {
"name": "season",
"description": "Season number (default: current)",
"choices": {
"current": "{season} (current)"
}
},
"league": {
"name": "league",
"description": "The league to display"
}
},
"body": {
"top_players": "Top {count} players",
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
"deleted_player": "Deleted {id}",
"neighbors": "Rating neighbors",
"more": "+ {count} more"
}
},
"today": {
"name": "今日",
"description": "Today's played tanks and statistics"
},
"stats": {
"name": "",
"description": "Quick statistics for a period"
},
"owned_tanks": {
"name": "owned-tanks",
"description": "Shows all own tanks in a tier",
"body": {
"title": "# {name}'s owned tier {tier} tanks\n\n"
}
},
"permissions": {
"name": "permissions",
"description": "Checks wether the bot has the required permissions to function",
"body": {
"title": "# Permissions\n\n{body}",
"view_channels": "View channels: needed to find the message the refresh button was used on",
"read_message_history": "Read message history: needed to find the message to refresh",
"attach_files": "Attach files: needed to add images to image-based commands",
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
}
},
"ping": {
"name": "ping",
"description": "Check wether the bot is alive.",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time}ms"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Ping BlitzKit"
},
"wotb": {
"name": "wotb",
"description": "Ping World of Tanks Blitz"
}
}
},
"player_info": {
"name": "player-info",
"description": "Basic information about a player",
"body": {
"title": "{name}'s information",
"nickname": "Nickname",
"battles": "戦闘数",
"winrate": "勝率",
"account_id": "Account ID",
"created": "Created",
"last_battle": "Last battle"
}
},
"rating": {
"name": "rating",
"description": "Rating player's statistics",
"subcommands": {
"today": {
"name": "今日",
"description": "Today's rating statistics"
},
"season": {
"name": "season",
"description": "This season's rating statistics"
}
},
"body": {
"subtitle": {
"today": "Today's rating statistics",
"season": "This season's rating statistics"
}
},
"errors": {
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
}
}
}
},
"website": {
"redirect": {
"title": "301: moved permanently",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "NEW",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
@@ -953,6 +492,7 @@
"tier": "Tier",
"type": "タイプ",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "購入価格",
"restoration": "再購入価格",
"sale": "売却価格",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "構成",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "モジュール",
"stock": "初期装備",
@@ -1005,8 +550,8 @@
"title": "性能値",
"compare": {
"label": "比較対象",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "全車輌"
},
"values": {
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "クリア",
"maximize": "最大"
"maximize": "最大",
"equalize": "Equalize"
},
"modules": {
"stock": "初期装備",
+47 -501
View File
@@ -1,6 +1,6 @@
{
"test": {
"default": "",
"default": "test",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.",
"fox": "Szybki brązowy lis przeskoczył nad leniwym psem."
},
@@ -17,9 +17,9 @@
"plus": "+{value}"
},
"gun_types": {
"auto_loader": "Auto loader",
"auto_loader": "Samo ładowacz",
"auto_reloader": "Automatyczne przeładowanie",
"regular": ""
"regular": "Regular"
},
"shells": {
"ap": "AP",
@@ -28,19 +28,20 @@
"he": "OB"
},
"player_count_period": {
"total": "Total",
"d_120": "Past 120 days",
"d_90": "Past 90 days",
"d_60": "Past 60 days",
"d_30": "Past month",
"total": "Łącznie",
"d_120": "Powyżej 120 dni",
"d_90": "Powyżej 90 dni",
"d_60": "Powyżej 60 dni",
"d_30": "W ciągu miesiąca",
"d_7": "W minionym tygodniu",
"d_1": "Yesterday"
"d_1": "Wczoraj"
},
"branches": {
"local": "dev",
"dev": "beta",
"opentest": "opentest",
"preview": "podgląd"
"beta": "Beta",
"development": "Development",
"opentest": "OpenTest",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Angielski",
@@ -80,45 +81,45 @@
},
"nations": {
"ussr": "ZSRR",
"germany": "Germany",
"usa": "U.S.A.",
"germany": "Niemcy",
"usa": "Stany Zjednoczone.",
"china": "Chiny",
"uk": "Wielka Brytania",
"france": "France",
"japan": "Japan",
"france": "Francja",
"japan": "Japonia",
"european": "Nacja Europejska",
"other": "Nacja Hybrydowa"
},
"nations_adjectives": {
"ussr": "ZSRR",
"germany": "German",
"germany": "Niemcy",
"usa": "Amerykański",
"china": "Chiński",
"uk": "Wielkiej Brytanii",
"france": "Francuski",
"japan": "Japoński",
"european": "European",
"other": "Hybrid"
"european": "Europa",
"other": "Hybryda"
},
"tank_class_short": {
"-1": "unrecognized",
"0": "Light",
"1": "Medium",
"2": "Heavy",
"0": "Lekki",
"1": "Średni",
"2": "Ciężki",
"3": "TD"
},
"tank_class_short_plural_lowercase": {
"0": "lights",
"1": "mediums",
"2": "heavies",
"0": "lekkie",
"1": "średnie",
"2": "ciężkie",
"3": "TDs"
},
"tank_class_medium": {
"-1": "unrecognized",
"0": "Lekki",
"1": "Medium",
"2": "Heavy",
"3": "Tank destroyer"
"1": "Średni",
"2": "Ciężki",
"3": "Niszczyciel czołgów"
},
"tree_type": {
"-1": "unrecognized",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Całkowity czas bitwy"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
"player_not_linked": "# Użyj `/link` aby zacząć\nNie wiem, kim jesteś, ale możesz mi dziś powiedzieć!",
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
"no_tank_stats": "# Brak dostępnych statystyk czołgów\nTen gracz nie ma żadnych dostępnych statystyk. Może to nie być gracz, którego szukasz.",
"get_help": "Pomóż serwerowi Discord",
"uncaught_error": "# BlitzKit wpadł w błąd!\nPrzepraszamy za to. Możesz [dołączyć do oficjalnego serwera Discord](https://discord.gg/nDt7AjGJQH), aby uzyskać pomoc.",
"preview": "# Ta komenda jest w podglądzie\n\nMożesz uzyskać dostęp do tej komendy tylko na [oficjalnym serwerze Discorda](https://discord.gg/nDt7AjGJQH). Polecenie będzie ogólnie dostępne wkrótce.",
"query_too_small": "# Twoje wyszukiwanie jest zbyt krótkie\nTwoje wyszukiwanie musi mieć co najmniej 3 znaki.",
"query_too_long": "# Twoje wyszukiwanie jest zbyt długie\nTwoje wyszukiwanie musi mieć maksymalnie 100 znaków."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Bardzo złe",
"bad": "Złe",
"below_average": "Poniżej średniej",
"average": "Średnia",
"above_average": "Powyżej średniej",
"good": "Dobrze",
"very_good": "Bardzo dobrze",
"great": "Świetne",
"unicum": "Unikalny ",
"super_unicum": "Bardzo unikalny"
}
},
"subcommands": {
"today": {
"name": "dziś",
"description": "Dziś"
},
"30": {
"name": "30",
"description": "30 dni"
},
"60": {
"name": "60",
"description": "60 dni"
},
"90": {
"name": "90",
"description": "90 dni"
},
"career": {
"name": "kariera",
"description": "Kariera"
},
"custom": {
"name": "Niestandardowy",
"description": "Zakres niestandardowy",
"options": {
"start": {
"name": "start",
"description": "Rozpocznij od dnia dzisiejszego"
},
"end": {
"name": "zakończ",
"description": "Zakończ od dnia dzisiejszego"
}
}
}
},
"options": {
"clan": {
"name": "klan",
"description": "Wpisz nazwę klanu lub tag"
},
"tank": {
"name": "czołg",
"description": "Czołg do pobrania statystyk"
},
"username": {
"name": "nazwa użytkownika",
"description": "Nazwa użytkownika Blitz gracza"
},
"filters": {
"nation": {
"name": "naród",
"description": "Naród"
},
"class": {
"name": "klasa",
"description": "Klasa"
},
"type": {
"name": "rodzaj",
"description": "Rodzaj"
}
},
"region": {
"name": "region",
"description": "Region"
},
"tier": {
"name": "poziom",
"description": "Poziom",
"choices": {
"tier": "Tier {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Kariera",
"today": "Dzisiaj",
"days": "{days} days",
"custom": "{day_1} - {day_2} days"
},
"filters": {
"none": "Brak filtrów",
"tier": "Tier {tier}"
},
"no_data": {
"battles_in_period": "Brak bitew w tym okresie",
"battles_in_season": "Brak bitew w tym sezonie",
"players_in_period": "Brak graczy w tym okresie",
"tanks_found": "Nie znaleziono czołgu"
},
"buttons": {
"refresh": "Odśwież"
},
"hero_stats": {
"battles": "Bitwy",
"winrate": "Zwycięstwa",
"damage": "Obrażenia",
"damage_ratio": "Współczynnik obrażeń",
"tier": "Poziom",
"survival": "Przeżycie",
"accuracy": "Celność",
"kills": "Zabójstwa"
}
},
"commands": {
"replay": {
"name": "powtórz",
"description": "Wyświetl wyniki powtórki"
},
"research": {
"name": "badanie",
"description": "Wyświetla wydatki na badanie linii",
"options": {
"target_tank": {
"name": "docelowy czołg",
"description": "Ostatni czołg do badań w linii"
},
"starting_tank": {
"name": "czołg rozpoczynający",
"description": "Czołg początkowy w linii (automatycznie, jeżeli nie jest dostarczony)"
}
},
"body": {
"subtitle": "Rozpocznij badania",
"total": "Całkowity",
"research": "Research: {cost}",
"upgrades": "Upgrades: {cost}",
"purchase": "Purchase: {cost}",
"equipment": "Equipment: {cost}",
"estimation": "# To jest szacunek!\n\nTa lista może zawierać już zbadane czołgi z powodu niedokładnych informacji dostarczanych przez Wargaming. Spróbuj podać `starting-tank` z wiersza podczas używania polecenia, jeśli możesz."
},
"errors": {
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
}
},
"about": {
"name": "opis",
"description": "Wszystkie informacje na temat bota",
"subcommands": {
"commands": {
"name": "komendy",
"description": "Lista wszystkich poleceń i ich opisów",
"body": "# Polecenia\n\nBlitzKit oferuje następujące polecenia:\n\n"
},
"embeds": {
"name": "osadzenie",
"description": "Jak działają osadzone"
},
"introduction": {
"name": "wprowadzenie",
"description": "O bocie"
},
"invite": {
"name": "zaproszenie",
"description": "Jak zaprosić bota"
},
"timezones": {
"name": "strefy czasowe",
"description": "W jaki sposób BlitzKit wnioskuje i wykorzystuje Twoją strefę czasową"
},
"credits": {
"name": "uznania",
"description": "Ludzie, którzy pomogli BlitzKit"
}
}
},
"breakdown": {
"name": "podział",
"description": "Podział przez okres według rozgrywanych czołgów",
"body": {
"total": "Ogółem",
"battles": "Bitwy",
"wn8": "WN8",
"winrate": "Śr. wygranych",
"damage": "Uszkodzenia",
"unknown_tank": "Unknown tank {id}"
}
},
"debug": {
"name": "debugowanie",
"description": "Debugowanie informacji o botu",
"body": {
"title": "# Debug\n\n",
"version": "Wersja",
"shard": {
"label": "Fragment",
"default": "domyślne"
},
"uptime": "Czas działania"
}
},
"evolution": {
"name": "rozwój",
"description": "Rozwój statystyk",
"groups": {
"player": {
"name": "gracz",
"description": "Statystyki gracza"
},
"tank": {
"name": "czołg",
"description": "Statystyki czołgu"
}
}
},
"inactive": {
"name": "inactive",
"description": "Lists all inactive players in a clan above a threshold",
"options": {
"threshold": {
"name": "threshold",
"description": "The number of days inactive (default: {days} days)"
}
},
"body": {
"subtitle": "Inactive for {days}+ days",
"listing": "{days} days"
}
},
"full_stats": {
"name": "full-stats",
"description": "Full in-game statistics",
"body": {
"cards": {
"games": {
"title": "Games",
"winrate": "Śr. wygranych",
"battles": "Bitwy",
"wins_losses": "Zwycięstwa / porażki"
},
"efficiency": {
"title": "Efficiency",
"wn8": "WN8",
"survival": "Przeżycie",
"accuracy": "Skuteczność"
},
"lethality": {
"title": "Lethality",
"average_damage": "Średnie uszkodzenia",
"damage_per_tier": "Damage per tier",
"damage_ratio": "Współczynnik obrażeń",
"average_kills": "Average kills"
},
"miscellaneous": {
"title": "Miscellaneous",
"average_tier": "Średni poziom",
"average_spots": "Average spots",
"average_xp": "Average XP",
"kills_to_death_ratio": "Stosunek zabójstw do śmierci"
}
}
}
},
"link": {
"name": "link",
"description": "Links your Blitz and Discord account",
"body": {
"accounts_linked": "Accounts linked",
"no_role_permissions": {
"title": "{name} failed to verify",
"description": "I don't have the permission to manage roles."
}
},
"embed": {
"title": "Incorrect account?",
"description": "Use the command again and select a username from the search results."
}
},
"search_clans": {
"name": "search-clans",
"description": "Search clans",
"options": {
"limit": {
"name": "",
"description": "The max number of clan results (default: {limit})"
}
},
"body": {
"title": "Clan search for {search} in region {region}",
"no_results": "No clans found"
}
},
"search_players": {
"name": "search-players",
"description": "Search players",
"options": {
"limit": {
"name": "",
"description": "The max number of player results (default: {limit})"
}
},
"body": {
"title": "Player search for {search} in region {region}",
"no_results": "No players found"
}
},
"rating_leaderboard": {
"name": "rating-leaderboard",
"description": "Rating battles statistics",
"subcommands": {
"neighbors": {
"name": "neighbors",
"description": "Neighboring players on the leaderboard"
},
"league": {
"name": "league",
"description": "Najlepsi gracze ligi"
}
},
"options": {
"limit": {
"name": "",
"description": "How many neighbors to display (default: {count})"
},
"season": {
"name": "season",
"description": "Season number (default: current)",
"choices": {
"current": "{season} (current)"
}
},
"league": {
"name": "league",
"description": "The league to display"
}
},
"body": {
"top_players": "Top {count} players",
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
"deleted_player": "Deleted {id}",
"neighbors": "Rating neighbors",
"more": "+ {count} more"
}
},
"today": {
"name": "dzisiaj",
"description": "Dzisiejsze zagrane czołgami i statystyki"
},
"stats": {
"name": "stats",
"description": "Szybkie statystyki na okres"
},
"owned_tanks": {
"name": "posiadane czołgi",
"description": "Pokazuje wszystkie własne czołgi na poziomie",
"body": {
"title": "# {name}'s owned tier {tier} tanks\n\n"
}
},
"permissions": {
"name": "uprawnienia",
"description": "Sprawdza, czy bot ma wymagane uprawnienia do funkcji",
"body": {
"title": "# Permissions\n\n{body}",
"view_channels": "Wyświetl kanały: potrzebne do znalezienia wiadomości użyty przycisk odświeżania",
"read_message_history": "Przeczytaj historię wiadomości: potrzebne do znalezienia wiadomości do odświeżenia",
"attach_files": "Dołącz pliki: potrzebne do dodawania obrazów do komend opartych na obrazach",
"external_emojis": "Zewnętrzne emotikony: potrzebne do dodania flagi krajowych i emotikonów klasy zbiorników"
}
},
"ping": {
"name": "ping",
"description": "Sprawdź, czy bot żyje.",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time}ms"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Ping BlitzKit"
},
"wotb": {
"name": "wotb",
"description": "Ping World of Tanks Blitz"
}
}
},
"player_info": {
"name": "informacje o graczu",
"description": "Podstawowe informacje o graczu",
"body": {
"title": "{name}'s information",
"nickname": "Nick",
"battles": "Bitwy",
"winrate": "Śr. wygranych",
"account_id": "ID konta",
"created": "Stworzony",
"last_battle": "Ostatnia bitwa"
}
},
"rating": {
"name": "klasyfikacja",
"description": "Statystyki klasyfikacji gracza",
"subcommands": {
"today": {
"name": "dzisiaj",
"description": "Dzisiejsze statystyki klasyfikacji"
},
"season": {
"name": "sezon",
"description": "Statystyki klasyfikacji w tym sezonie"
}
},
"body": {
"subtitle": {
"today": "Dzisiejsze statystyki klasyfikacji",
"season": "Statystyki klasyfikacji w tym sezonie"
}
},
"errors": {
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
}
}
}
},
"website": {
"redirect": {
"title": "301: moved permanently",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "NEW",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
@@ -849,7 +388,7 @@
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Medium",
"medium": "Średni",
"soft": "Soft",
"effective": "Effective"
},
@@ -953,6 +492,7 @@
"tier": "Poziom",
"type": "Rodzaj",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Purchase price",
"restoration": "Restoration price",
"sale": "Sale price",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "Configuration",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Modules",
"stock": "Stock",
@@ -1005,8 +550,8 @@
"title": "Characteristics",
"compare": {
"label": "Compare against",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "All tanks"
},
"values": {
@@ -1059,19 +604,19 @@
"speedBackwards": "Backwards",
"hardTerrainCoefficient": "Hard",
"hardTerrainCoefficientRaw": "Hard",
"mediumTerrainCoefficient": "Medium",
"mediumTerrainCoefficientRaw": "Medium",
"mediumTerrainCoefficient": "Średni",
"mediumTerrainCoefficientRaw": "Średni",
"softTerrainCoefficient": "Soft",
"softTerrainCoefficientRaw": "Soft",
"enginePower": "Engine power",
"powerToWeightRatioHardTerrain": "Hard",
"powerToWeightRatioMediumTerrain": "Medium",
"powerToWeightRatioMediumTerrain": "Średni",
"powerToWeightRatioSoftTerrain": "Soft",
"weight": "Weight",
"turretTraverseSpeed": "Turret traverse speed",
"gunTraverseSpeed": "Gun traverse speed",
"hullTraverseHardTerrain": "Hard",
"hullTraverseMediumTerrain": "Medium",
"hullTraverseMediumTerrain": "Średni",
"hullTraverseSoftTerrain": "Soft",
"health": "Health",
"fireChance": "Fire chance",
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Clear",
"maximize": "Maximize"
"maximize": "Maximize",
"equalize": "Equalize"
},
"modules": {
"stock": "Stock",
@@ -1174,7 +720,7 @@
"table": {
"tanks": {
"header": "Tank",
"total": "Total"
"total": "Łącznie"
},
"stats": {
"winrate": "Śr. wygranych",
@@ -1232,7 +778,7 @@
},
"table": {
"tank": "Tank",
"total": "Total",
"total": "Łącznie",
"remove": "Remove"
}
},
+15 -469
View File
@@ -37,10 +37,11 @@
"d_1": "Ontem"
},
"branches": {
"local": "dev",
"dev": "beta",
"opentest": "testeaberto",
"preview": "visualização"
"beta": "Beta",
"development": "Development",
"opentest": "TesteAberto",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Inglês",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Tempo de batalha total"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Could not find clan\nCouldn't find \"{search}\". Try selecting a clan from the search result.",
"player_not_found": "# Could not find user\nI couldn't find user \"{search}\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
"player_not_linked": "Digite \"/link\" para começar.\nEu posso não saber quem é você, mas pode-me dizer hoje sobre isso!",
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"{search}\".",
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"{search}\". Try typing the name of the tank instead of a number.",
"no_tank_stats": "# Nenhuma estatística de tanques disponível\nEsse jogador não tem as suas estatísticas disponíveis. Talvez esse pode não ser o jogador que procura.",
"get_help": "Servidor de Ajuda no Discord",
"uncaught_error": "# O BlitzKit apresentou um erro!\nSentimos muito por isso. Sinta-se a vontade para [entrar no servidor oficial no Discord]\n(https://discord.gg/nDt7AjGJQH) para conseguir ajuda.",
"preview": "# Este comando está na pré-visualização\n\nVocê só pode acessar este comando no [servidor oficial do Discord](https://discord.gg/nDt7AjGJQH). O comando estará geralmente disponível em breve.",
"query_too_small": "# Sua pesquisa é muito curta\nSua pesquisa deve ter pelo menos 3 caracteres.",
"query_too_long": "# Sua pesquisa é muito longa\nSua pesquisa deve ter no máximo 100 caracteres."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Muito ruim",
"bad": "Ruim",
"below_average": "Abaixo da média",
"average": "Na média",
"above_average": "Acima da média",
"good": "Bom",
"very_good": "Muito bom",
"great": "Ótimo",
"unicum": "Unicum",
"super_unicum": "Super unicum"
}
},
"subcommands": {
"today": {
"name": "hoje",
"description": "Hoje"
},
"30": {
"name": "30",
"description": "30 dias"
},
"60": {
"name": "60",
"description": "60 dias"
},
"90": {
"name": "90",
"description": "90 dias"
},
"career": {
"name": "carreira",
"description": "Carreira"
},
"custom": {
"name": "personalizado",
"description": "Intervalo personalizado",
"options": {
"start": {
"name": "iniciar",
"description": "Iniciar em número de dias atrás a partir de hoje"
},
"end": {
"name": "terminar",
"description": "Termina em número de dias atrás a partir de hoje"
}
}
}
},
"options": {
"clan": {
"name": "clã",
"description": "O nome ou tag do clã"
},
"tank": {
"name": "tanque",
"description": "O tanque para obter estatísticas para"
},
"username": {
"name": "nome de usuário",
"description": "O nome de usuário Blitz do jogador"
},
"filters": {
"nation": {
"name": "nação",
"description": "Nação"
},
"class": {
"name": "classe",
"description": "Classe"
},
"type": {
"name": "tipo",
"description": "Tipo"
}
},
"region": {
"name": "região",
"description": "Região"
},
"tier": {
"name": "nível",
"description": "Nível",
"choices": {
"tier": "Tier {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Carreira",
"today": "Hoje",
"days": "{days} days",
"custom": "{day_1} - {day_2} days"
},
"filters": {
"none": "Sem filtros",
"tier": "Tier {tier}"
},
"no_data": {
"battles_in_period": "Não há batalhas jogadas neste período",
"battles_in_season": "Não há batalhas jogadas nesta temporada",
"players_in_period": "Nenhum jogador neste período",
"tanks_found": "Nenhum tanque encontrado"
},
"buttons": {
"refresh": "Atualizar"
},
"hero_stats": {
"battles": "Batalhas",
"winrate": "Taxa de vitória",
"damage": "Dano",
"damage_ratio": "Razão entre dano dado e recebido",
"tier": "Nível",
"survival": "Sobrevivência",
"accuracy": "Precisão",
"kills": "Abates"
}
},
"commands": {
"replay": {
"name": "replay",
"description": "Exibir resultados de replays"
},
"research": {
"name": "pesquisa",
"description": "Liste as despesas na pesquisa de uma linha",
"options": {
"target_tank": {
"name": "tanque-alvo",
"description": "O último tanque para pesquisar na linha"
},
"starting_tank": {
"name": "tanque-inicial",
"description": "O tanque inicial na linha (inferido automaticamente se não fornecido)"
}
},
"body": {
"subtitle": "Pesquisa",
"total": "Total",
"research": "Research: {cost}",
"upgrades": "Upgrades: {cost}",
"purchase": "Purchase: {cost}",
"equipment": "Equipment: {cost}",
"estimation": "# Esta é uma estimativa!\n\nEsta lista pode incluir tanques já pesquisados devido à informação imprecisa que a Wargaming fornece. Tente fornecer um `tanque-inicial` da linha ao usar o comando, se puder."
},
"errors": {
"non_tech_tree": "# {tank} is not on the tech tree\n\nYou cannot research a premium/collector tank.",
"tier_1": "# {tank} is a tier I\n\nTier I tanks are always unlocked for free for all players.",
"already_researched": "# {tank} is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
"start_end_equal": "# {tank} was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
"tanks_not_on_line": "# {tank_1} and {tank_2} are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
"unordered": "# {tank_1} higher tiered to {tank_2}\n\nMake sure to provide {tank_2} as the `starting-tank` instead as it is the lower tiered tank."
}
},
"about": {
"name": "sobre",
"description": "Todas as informações que você precisa sobre o bot",
"subcommands": {
"commands": {
"name": "comandos",
"description": "Lista de todos os comandos e suas descrições",
"body": "# Comandos\n\nBlitzKit oferece os seguintes comandos:\n"
},
"embeds": {
"name": "incorporar",
"description": "Como incorporações funcionam"
},
"introduction": {
"name": "Introdução",
"description": "Sobre o bot"
},
"invite": {
"name": "convite",
"description": "Como convidar o bot"
},
"timezones": {
"name": "fusos horários",
"description": "Como o BlitzKit inferi e usa seu fuso horário"
},
"credits": {
"name": "créditos",
"description": "Pessoas que ajudaram BlitzKit"
}
}
},
"breakdown": {
"name": "divisão",
"description": "Análise de um período por tanques jogados",
"body": {
"total": "Total",
"battles": "Batalhas",
"wn8": "WN8",
"winrate": "Taxa de vitória",
"damage": "Dano",
"unknown_tank": "Unknown tank {id}"
}
},
"debug": {
"name": "depuração",
"description": "Depurar informações sobre o bot",
"body": {
"title": "# Depuração\n",
"version": "Versão",
"shard": {
"label": "Fragmento",
"default": "padrão"
},
"uptime": "Tempo de atividade"
}
},
"evolution": {
"name": "evolução",
"description": "Evolução das estatísticas",
"groups": {
"player": {
"name": "jogador",
"description": "Estatísticas do Jogador"
},
"tank": {
"name": "tanque",
"description": "Estatísticas do tanque"
}
}
},
"inactive": {
"name": "inativo",
"description": "Liste todos os jogadores inativos em um clã acima de um limite",
"options": {
"threshold": {
"name": "limite",
"description": "The number of days inactive (default: {days} days)"
}
},
"body": {
"subtitle": "Inactive for {days}+ days",
"listing": "{days} days"
}
},
"full_stats": {
"name": "estatísticas-completas",
"description": "Estatísticas completas dentro do jogo",
"body": {
"cards": {
"games": {
"title": "Jogos",
"winrate": "Taxa de vitória",
"battles": "Batalhas",
"wins_losses": "Vitórias / Derrotas"
},
"efficiency": {
"title": "Eficiência",
"wn8": "WN8",
"survival": "Sobrevivência",
"accuracy": "Precisão"
},
"lethality": {
"title": "Letalidade",
"average_damage": "Dano médio",
"damage_per_tier": "Dano por nível",
"damage_ratio": "Razão entre dano dado e recebido",
"average_kills": "Média de abates"
},
"miscellaneous": {
"title": "Diversos",
"average_tier": "Nível médio",
"average_spots": "Média de detecções",
"average_xp": "EXP Médio",
"kills_to_death_ratio": "Razão entre abates e mortes"
}
}
}
},
"link": {
"name": "link",
"description": "Conecte sua conta Blitz e Discord",
"body": {
"accounts_linked": "Contas vinculadas",
"no_role_permissions": {
"title": "{name} failed to verify",
"description": "Eu não tenho permissão para gerenciar funções."
}
},
"embed": {
"title": "Conta incorreta?",
"description": "Use o comando novamente e selecione um nome de usuário dos resultados da pesquisa."
}
},
"search_clans": {
"name": "procurar-clãs",
"description": "Procurar clãs",
"options": {
"limit": {
"name": "limite",
"description": "The max number of clan results (default: {limit})"
}
},
"body": {
"title": "Clan search for {search} in region {region}",
"no_results": "Nenhum clã encontrado"
}
},
"search_players": {
"name": "pesquisa-jogadores",
"description": "Procurar jogadores",
"options": {
"limit": {
"name": "limite",
"description": "The max number of player results (default: {limit})"
}
},
"body": {
"title": "Player search for {search} in region {region}",
"no_results": "Nenhum jogador encontrado"
}
},
"rating_leaderboard": {
"name": "classificação-tabela de classificação",
"description": "Estatísticas de batalhas de classificação",
"subcommands": {
"neighbors": {
"name": "vizinhos",
"description": "Jogadores vizinhos na tabela de classificação"
},
"league": {
"name": "Liga",
"description": "Melhores jogadores de uma liga"
}
},
"options": {
"limit": {
"name": "limite",
"description": "How many neighbors to display (default: {count})"
},
"season": {
"name": "temporada",
"description": "Número da temporada (padrão: atual)",
"choices": {
"current": "{season} (current)"
}
},
"league": {
"name": "Liga",
"description": "A liga para exibir"
}
},
"body": {
"top_players": "Top {count} players",
"no_participation": "# {player} didn't play rating in season {season}\n\nThis player did not participate in this season or did not get past calibration.",
"no_ongoing_season": "# Nenhuma temporada em andamento\n\nNão há uma temporada de classificação em execução no momento.",
"deleted_player": "Deleted {id}",
"neighbors": "Classificação de vizinhos",
"more": "+ {count} more"
}
},
"today": {
"name": "hoje",
"description": "Tanques jogados hoje e estatísticas"
},
"stats": {
"name": "estatísticas",
"description": "Estatísticas rápidas para um período"
},
"owned_tanks": {
"name": "tanques-possuídos",
"description": "Mostra todos os tanques possuídos em um nível",
"body": {
"title": "# {name}'s owned tier {tier} tanks\n\n"
}
},
"permissions": {
"name": "Permissões",
"description": "Verifica se o bot tem as permissões necessárias para funcionar",
"body": {
"title": "# Permissions\n\n{body}",
"view_channels": "Ver canais: necessário para encontrar a mensagem em que o botão atualizar foi usado",
"read_message_history": "Histórico de mensagens lidas: necessário para encontrar a mensagem para atualizar",
"attach_files": "Anexar arquivos: necessário para adicionar imagens a comandos baseados em imagens",
"external_emojis": "Emojis externos: necessário para adicionar bandeiras nacionais e emojis de classe de tanque"
}
},
"ping": {
"name": "ping",
"description": "Verifique se o bot está vivo.",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time}ms"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Ping BlitzKit"
},
"wotb": {
"name": "wotb",
"description": "Ping World of Tanks Blitz"
}
}
},
"player_info": {
"name": "informação do jogador",
"description": "Informações básicas sobre um jogador",
"body": {
"title": "{name}'s information",
"nickname": "Apelido",
"battles": "Batalhas",
"winrate": "Taxa de vitória",
"account_id": "ID da conta",
"created": "Criado",
"last_battle": "Última batalha"
}
},
"rating": {
"name": "classificação",
"description": "Estatísticas de jogador de classificação",
"subcommands": {
"today": {
"name": "hoje",
"description": "Estatísticas de classificação hoje"
},
"season": {
"name": "temporada",
"description": "Estatísticas de classificação desta temporada"
}
},
"body": {
"subtitle": {
"today": "Estatísticas de classificação hoje",
"season": "Estatísticas de classificação desta temporada"
}
},
"errors": {
"no_participation": "# {name} hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
"unrecorded_stats": "# Estatísticas atualmente indisponível\n\nWargaming pode estar no momento, enfrentando tempo de inatividade do servidor. Se houver uma temporada em curso, as estatísticas deverão ser disponibilizadas dentro de 24 horas."
}
}
}
},
"website": {
"redirect": {
"title": "301: moved permanently",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "NEW",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
@@ -953,6 +492,7 @@
"tier": "Nível",
"type": "Tipo",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Preço de compra",
"restoration": "Preço de recuperação",
"sale": "Preço de venda",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "Configuração",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Módulos",
"stock": "Padrão",
@@ -1005,8 +550,8 @@
"title": "Características",
"compare": {
"label": "Comparar com",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "Todos os tanques"
},
"values": {
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Limpar",
"maximize": "Maximizar"
"maximize": "Maximizar",
"equalize": "Equalize"
},
"modules": {
"stock": "Padrão",
+16 -470
View File
@@ -37,10 +37,11 @@
"d_1": "Вчера"
},
"branches": {
"local": "dev",
"dev": "бета",
"opentest": "общий тест",
"preview": "превью"
"beta": "Бета",
"development": "Development",
"opentest": "Открытый тест",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Английский",
@@ -139,7 +140,7 @@
}
},
"leagues": {
"diamond": "Диамантовая",
"diamond": "Алмазная",
"platinum": "Платиновая",
"gold": "Золотая",
"silver": "Серебряная",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Общее время в боях"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Не удалось найти клан\nНе найден «{search}». Попробуйте выбрать клан из результатов поиска.",
"player_not_found": "# Не удалось найти пользователя\nНе удалось найти пользователя «{search}». Попробуйте выбрать пользователя из результатов поиска, введя правильное имя пользователя или используя команду «/link».",
"player_not_linked": "# Используйте «/link», чтобы начать\nЯ не знаю, кто ты, но давай познакомимся сегодня!",
"tank_name_not_found": "# Танк не найден\nНе удалось найти танк с названием «{search}».",
"tank_id_not_found": "# Танк не найден\nНе удалось найти танк с ID «{search}». Попробуйте ввести название танка вместо числа.",
"no_tank_stats": "# Статистика танка недоступна\nУ этого игрока нет доступной статистики. Возможно, это не тот игрок, которого вы ищете.",
"get_help": "Получить помощь",
"uncaught_error": "# BlitzKit столкнулся с ошибкой!\nНам очень жаль. Не стесняйтесь и [присоединяйтесь к официальному серверу Discord](https://discord.gg/nDt7AjGJQH), чтобы получить помощь.",
"preview": "# Эта команда находится в тестируется\n\nВы можете получить доступ к этой команде только на [официальном сервере Discord] (https://discord.gg/nDt7AjGJQH). Команда скоро станет общедоступной.",
"query_too_small": "# Ваш поисковой запрос слишком короткий\nДлина вашего запроса должна составлять не менее 3 символов.",
"query_too_long": "# Ваш поисковой запрос слишком длинный\nДлина вашего запроса должна составлять не более 100 символов."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Очень плохо",
"bad": "Плохо",
"below_average": "Ниже среднего",
"average": "Средне",
"above_average": "Выше среднего",
"good": "Хорошо",
"very_good": "Очень хорошо",
"great": "Отлично",
"unicum": "Уникально",
"super_unicum": "Крайне уникально"
}
},
"subcommands": {
"today": {
"name": "cегодня",
"description": "Cегодня"
},
"30": {
"name": "30",
"description": "30 дней"
},
"60": {
"name": "60",
"description": "60 дней"
},
"90": {
"name": "90",
"description": "90 дней"
},
"career": {
"name": "карьера",
"description": "Карьера"
},
"custom": {
"name": "пользовательский",
"description": "Собственный диапазон",
"options": {
"start": {
"name": "начать",
"description": "Начать через N дней с сегодняшнего дня"
},
"end": {
"name": "конец",
"description": "Закончить через N дней с сегодняшнего дня"
}
}
}
},
"options": {
"clan": {
"name": "клан",
"description": "Название или тег клана"
},
"tank": {
"name": "танк",
"description": "Танк для получения статистики для"
},
"username": {
"name": "ник",
"description": "Ник игрока в Blitz"
},
"filters": {
"nation": {
"name": "нация",
"description": "Нация"
},
"class": {
"name": "класс",
"description": "Класс"
},
"type": {
"name": "тип",
"description": "Тип"
}
},
"region": {
"name": "регион",
"description": "Регион"
},
"tier": {
"name": "уровень",
"description": "Уровень",
"choices": {
"tier": "Уровень {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Карьера",
"today": "Cегодня",
"days": "{days} дней",
"custom": "{day_1} - {day_2} дней"
},
"filters": {
"none": "Без фильтров",
"tier": "{tier} уровень"
},
"no_data": {
"battles_in_period": "За этот период боёв не было",
"battles_in_season": "За этот сезон боёв не было",
"players_in_period": "Нет игроков за этот период",
"tanks_found": "Танки не найдены"
},
"buttons": {
"refresh": "Обновить"
},
"hero_stats": {
"battles": "Боёв",
"winrate": "Коэффициент побед",
"damage": "Урон",
"damage_ratio": "Коэффициент урона",
"tier": "Уровень",
"survival": "Выживание",
"accuracy": "Точность стрельбы",
"kills": "Уничтожил"
}
},
"commands": {
"replay": {
"name": "повтор",
"description": "Показать результаты повтора"
},
"research": {
"name": "исследование",
"description": "Список ресурсов для исследования ветки",
"options": {
"target_tank": {
"name": "желаемый танк",
"description": "Желаемый танк ветки исследования"
},
"starting_tank": {
"name": "стартовый-танк",
"description": "Стартовый танк в ветке (назначен автоматически, если не установлен)"
}
},
"body": {
"subtitle": "Исследование",
"total": "Всего",
"research": "Исследование: {cost}",
"upgrades": "Улучшения: {cost}",
"purchase": "Покупка: {cost}",
"equipment": "Снаряжение: {cost}",
"estimation": "# Это приблизительная оценка!\n\nВ этот список могут входить уже исследованные танки из-за неточной информации, предоставляемой Wargaming. Попробуйте указать «стартовый-танк» в строке при использовании команды, если сможете."
},
"errors": {
"non_tech_tree": "# {tank} отсутствует в дереве танков\n\nВы не можете исследовать премиумный / коллекционный танк.",
"tier_1": "# {tank} — танк I уровня\n\nУровень I всегда открыт бесплатно для всех игроков.",
"already_researched": "# {tank} уже исследован\n\nПопробуйте предоставить «starting-tank» при использовании команды для просмотра итогов уже исследованной ветки.",
"start_end_equal": "# {tank} был предоставлен дважды\n\nУбедитесь, что «starting-tank» и «target-tank» различаются.",
"tanks_not_on_line": "# {tank_1} и {tank_2} находятся не в одной ветке\n\nУбедитесь, что «starting-tank» и «target-tank» находятся на той же ветке дерева танков.",
"unordered": "# У {tank_1} более высокий уровень чем у {tank_2}\n\nОбязательно укажите {tank_2} в качестве «starting-tank», так как это танк более низкого уровня."
}
},
"about": {
"name": "о-боте",
"description": "Вся необходимая информация о боте",
"subcommands": {
"commands": {
"name": "команды",
"description": "Список всех команд и их описаний",
"body": "# Команды\n\nBlitzKit предлагает следующие команды:\n\n"
},
"embeds": {
"name": "встраиваемые-элементы",
"description": "Как работают встраиваемые элементы"
},
"introduction": {
"name": "введение",
"description": "О боте"
},
"invite": {
"name": "пригласить",
"description": "Как пригласить бота"
},
"timezones": {
"name": "часовой-пояс",
"description": "Как BlitzKit определяет и использует ваш часовой пояс"
},
"credits": {
"name": "авторы",
"description": "Люди, которые помогли BlitzKit"
}
}
},
"breakdown": {
"name": "распределение",
"description": "Статистика игр за период с распределением по танкам",
"body": {
"total": "Всего",
"battles": "Боёв",
"wn8": "WN8",
"winrate": "Коэффициент побед",
"damage": "Урон",
"unknown_tank": "Неизвестный танк {id}"
}
},
"debug": {
"name": "отладка",
"description": "Сведения для отладки",
"body": {
"title": "# Отладка",
"version": "Версия",
"shard": {
"label": "Фрагмент",
"default": "по умолчанию"
},
"uptime": "Время работы"
}
},
"evolution": {
"name": "изменения",
"description": "Изменения статистики",
"groups": {
"player": {
"name": "игрок",
"description": "Статистика игрока"
},
"tank": {
"name": "танк",
"description": "Статистика танков"
}
}
},
"inactive": {
"name": "неактивно",
"description": "Список всех неактивных игроков в клане выше порога",
"options": {
"threshold": {
"name": "порог",
"description": "Количество дней не активности (по умолчанию: {days} дней)"
}
},
"body": {
"subtitle": "Неактивен {days}+ дней",
"listing": "{days} дней"
}
},
"full_stats": {
"name": "полная-статистика",
"description": "Полная игровая статистика",
"body": {
"cards": {
"games": {
"title": "Игры",
"winrate": "Коэффициент побед",
"battles": "Боёв",
"wins_losses": "Побед / поражений"
},
"efficiency": {
"title": "Эффективность",
"wn8": "WN8",
"survival": "Выжил",
"accuracy": "Точность стрельбы"
},
"lethality": {
"title": "Смертность",
"average_damage": "Средний урон",
"damage_per_tier": "Урон по уровню",
"damage_ratio": "Коэффициент урона",
"average_kills": "Среднее число уничтоженных"
},
"miscellaneous": {
"title": "Прочее",
"average_tier": "Средний уровень",
"average_spots": "Среднее число попаданий",
"average_xp": "Средний опыт",
"kills_to_death_ratio": "Коэффициент убийств и смертей"
}
}
}
},
"link": {
"name": "ссылка",
"description": "Привяжите учётную запись Blitz и Discord",
"body": {
"accounts_linked": "Аккаунты привязаны",
"no_role_permissions": {
"title": "{name} не удалось проверить",
"description": "У меня нет разрешения на управление ролями."
}
},
"embed": {
"title": "Неверный аккаунт?",
"description": "Используйте команду снова и выберите имя пользователя из результатов поиска."
}
},
"search_clans": {
"name": "поиск-кланов",
"description": "Поиск кланов",
"options": {
"limit": {
"name": "лимит",
"description": "Максимальное количество результатов клана (по умолчанию: {limit})"
}
},
"body": {
"title": "Поиск клана {search} в регионе {region}",
"no_results": "Кланов не найдено"
}
},
"search_players": {
"name": "поиск-игроков",
"description": "Поиск игроков",
"options": {
"limit": {
"name": "лимит",
"description": "Максимальное число результатов игрока (по умолчанию: {limit})"
}
},
"body": {
"title": "Поиск игрока {search} в регионе {region}",
"no_results": "Игроков не найдено"
}
},
"rating_leaderboard": {
"name": "таблица-лидеров",
"description": "Статистика рейтингов боёв",
"subcommands": {
"neighbors": {
"name": "ближайшие",
"description": "Ближайшие игроки в таблице лидеров"
},
"league": {
"name": "лига",
"description": "Топ игроков лиги"
}
},
"options": {
"limit": {
"name": "лимит",
"description": "Количество отображаемых ближайших игроков (по умолчанию: {count})"
},
"season": {
"name": "сезон",
"description": "Номер сезона (по умолчанию: текущий)",
"choices": {
"current": "{season} (текущий)"
}
},
"league": {
"name": "лига",
"description": "Отображаемая лига"
}
},
"body": {
"top_players": "Топ {count} игроков",
"no_participation": "# {player} не играл в рейтинг в сезоне {season}\n\nЭтот игрок не участвовал в этом сезоне или не получил прошлую калибровку.",
"no_ongoing_season": "# Нет текущего сезона\n\nВ данный момент нет рейтингового сезона.",
"deleted_player": "Удаленный {id}",
"neighbors": "Рейтинг ближайших игроков",
"more": "+ ещё {count}"
}
},
"today": {
"name": "cегодня",
"description": "Танки, на которых сыграли сегодня и статистика"
},
"stats": {
"name": "статистика",
"description": "Быстрая статистика за период"
},
"owned_tanks": {
"name": "cобственные-танки",
"description": "Показывает все принадлежащие танки на уровне",
"body": {
"title": "# {name} принадлежат танки {tier} уровня\n\n"
}
},
"permissions": {
"name": "разрешения",
"description": "Проверяет, есть ли у бота необходимые разрешения для работы",
"body": {
"title": "# Разрешения\n\n{body}",
"view_channels": "Просмотр каналов: необходимо найти сообщение, на котором была использована кнопка обновления",
"read_message_history": "Просмотр истории сообщений: необходимо найти сообщение для обновления",
"attach_files": "Прикрепить файлы: необходимо для добавления изображений в команды на основе изображения",
"external_emojis": "Внешние эмоции: необходимы для добавления национальных флагов и эмодзи класса танков"
}
},
"ping": {
"name": "пинг",
"description": "Проверьте, что бот жив.",
"body": {
"pong": "Понг 🏓",
"pong_with_time": "Понг 🏓 — {time}мс"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "Пинг BlitzKit"
},
"wotb": {
"name": "wotb",
"description": "Пинг World of Tanks Blitz"
}
}
},
"player_info": {
"name": "информация-об-игроке",
"description": "Основная информация о игроке",
"body": {
"title": "Информация о {name}",
"nickname": "Никнейм",
"battles": "Боёв",
"winrate": "Коэффициент побед",
"account_id": "ID учётной записи",
"created": "Создано",
"last_battle": "Последний бой"
}
},
"rating": {
"name": "рейтинг",
"description": "Статистика рейтинга игрока",
"subcommands": {
"today": {
"name": "cегодня",
"description": "Статистика рейтинга за сегодня"
},
"season": {
"name": "сезон",
"description": "Статистика рейтинга в этом сезоне"
}
},
"body": {
"subtitle": {
"today": "Статистика рейтинга за сегодня",
"season": "Статистика рейтинга в этом сезоне"
}
},
"errors": {
"no_participation": "# {name} не получил рейтинга\n\nЭтот игрок в этом сезоне не участвовал в рейтинговом режиме.",
"unrecorded_stats": "# Статистика недоступна в настоящее время\n\nВ настоящее время Wargaming, возможно, сталкивается с простоями сервера. Если сезон продолжается, статистика должна быть доступна в течение 24 часов."
}
}
}
},
"website": {
"redirect": {
"title": "301: перемещено навсегда",
@@ -734,14 +281,6 @@
}
},
"home": {
"pwa": {
"title": "Установите приложение BlitzKit",
"new": "НОВИНКА",
"checking": "Проверка совместимости...",
"instructions": "Инструкция для устройств Apple.",
"install": "Установка",
"dismiss": "Отклонить"
},
"discord": {
"join_short": "Присоединяйтесь к крутым ребятам!",
"join_long": "Присоединяйся к супер-дупер крутым ребятам!",
@@ -817,7 +356,7 @@
"skip": "Пропустить",
"guess": "Угадать",
"next": "Следующий",
"no_results": "Ничего не найденo"
"no_results": "Ничего не найдено"
},
"stats": "{correct} / {total} правильно, серия: {streak}",
"help": {
@@ -953,6 +492,7 @@
"tier": "Уровень",
"type": "Тип",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Цена покупки",
"restoration": "Цена восстановления",
"sale": "Цена продажи",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "Конфигурация",
"equalizer": {
"title": "Уравнение",
"equalize": "Уравнять",
"beta": "Бета"
},
"modules": {
"title": "Модули",
"stock": "Сток",
@@ -1005,7 +550,7 @@
"title": "Характеристики",
"compare": {
"label": "Сравнивать с",
"class": "{class} {tier} уровня",
"class": "{tier} {class}",
"tier": "Все {tier} уровня",
"all": "Все танки"
},
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Очистить",
"maximize": "Максимум"
"maximize": "Максимум",
"equalize": "Уравнять"
},
"modules": {
"stock": "Сток",
+68 -522
View File
@@ -1,7 +1,7 @@
{
"test": {
"default": "тест",
"long": "{fruit}",
"long": "{color}{fruit}",
"fox": "Швидка бура лисиця перестрибує через лінивого собаку."
},
"common": {
@@ -23,7 +23,7 @@
},
"shells": {
"ap": "ББ",
"ap_cr": "APCR",
"ap_cr": "",
"hc": "HEAT",
"he": "ОФ"
},
@@ -37,10 +37,11 @@
"d_1": "Вчора"
},
"branches": {
"local": "розробник",
"dev": "бета",
"opentest": "відкритий тест",
"preview": "попередній перегляд"
"beta": "Beta",
"development": "Development",
"opentest": "Відкритий тест",
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "Англійська",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "Загальний час бою"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# Не вдалося знайти клан\nНе вдалося знайти \"{search}\". Спробуйте обрати клан з результату пошуку.",
"player_not_found": "# Не вдалося знайти користувача\nНе вдалося знайти користувача \"{search}\". Спробуйте вибрати користувача із результатів пошуку, ввівши правильне ім'я користувача, або скористайтеся командою `/link`.",
"player_not_linked": "# Використайте команду \"/link\" щоб почати\nЯ не знаю, хто ви, але ви можете сказати мені сьогодні!",
"tank_name_not_found": "# Танк не знайдено\nНе вдалося знайти танк із назвою «{search}».",
"tank_id_not_found": "# Танк не знайдено\nНе вдалося знайти танк з ID «{search}». Спробуйте ввести назву танка замість номера.",
"no_tank_stats": "# Немає статистики для танка\nЦей гравець не має статистики.\nМожливо, це не той гравець, якого ви шукаєте.",
"get_help": "Допомогти Discord серверу",
"uncaught_error": "# Упс! BlitzKit зіткнувся з помилкою!\nНам дуже шкода. Можете попросити допомоги на [офіційному сервері Discord](https://discord.gg/nDt7AjGJQH).",
"preview": "# Ця команда є в попередньому перегляді\n\nВи можете отримати доступ лише до цієї команди на [офіційному сервері Discord](https://discord.gg/nDt7AjGJQH). Команда в цілому буде доступна найближчим часом.",
"query_too_small": "# Ваш пошук занадто короткий\nВаш пошук повинен бути щонайменше 3 символи.",
"query_too_long": "# Ваш пошук занадто довгий\nВаш пошук повинен бути щонайбільше 100 символи."
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "Дуже погано",
"bad": "Погано",
"below_average": "Нижче середнього",
"average": "Середнє",
"above_average": "Вище середнього",
"good": "Добре",
"very_good": "Дуже добре",
"great": "Відмінно",
"unicum": "Винятковий",
"super_unicum": "Супер винятковий"
}
},
"subcommands": {
"today": {
"name": "сьогодні",
"description": "Сьогодні"
},
"30": {
"name": "30",
"description": "30 днів"
},
"60": {
"name": "60",
"description": "60 днів"
},
"90": {
"name": "90",
"description": "90 днів"
},
"career": {
"name": "кар'єра",
"description": "Кар'єра"
},
"custom": {
"name": "користувацьке",
"description": "Власний діапазон",
"options": {
"start": {
"name": "почати",
"description": "Початок за кількістю днів тому від сьогодні"
},
"end": {
"name": "кінець",
"description": "Кінець за кількістю днів тому від сьогодні"
}
}
}
},
"options": {
"clan": {
"name": "клан",
"description": "Назва клану або тег"
},
"tank": {
"name": "танк",
"description": "Танк для якого треба отримати статистику"
},
"username": {
"name": "ім'я користувача",
"description": "Бліц ім'я гравця"
},
"filters": {
"nation": {
"name": "нація",
"description": "Нація"
},
"class": {
"name": "клас",
"description": "Клас"
},
"type": {
"name": "вид",
"description": "Вид"
}
},
"region": {
"name": "регіон",
"description": "Регіон"
},
"tier": {
"name": "рівень",
"description": "Рівень",
"choices": {
"tier": "Рівень {tier_1} - {tier_2}"
}
}
},
"periods": {
"career": "Кар'єра",
"today": "Сьогодні",
"days": "{days} днів",
"custom": "{day_1} - {day_2} днів"
},
"filters": {
"none": "Немає фільтрів",
"tier": "Рівень {tier}"
},
"no_data": {
"battles_in_period": "За цей період боїв не було",
"battles_in_season": "У цьому сезоні боїв не було",
"players_in_period": "Немає гравців за цей період",
"tanks_found": "Жодних танків не знайдено"
},
"buttons": {
"refresh": "Оновити"
},
"hero_stats": {
"battles": "Бої",
"winrate": "Відсоток перемог",
"damage": "Шкода",
"damage_ratio": "Коефіцієнт шкоди",
"tier": "Рівень",
"survival": "Виживання",
"accuracy": "Точність",
"kills": "Знищено"
}
},
"commands": {
"replay": {
"name": "реплей",
"description": "Показати результати реплею"
},
"research": {
"name": "дослідження",
"description": "Показує витрати в дослідженні гілки",
"options": {
"target_tank": {
"name": "цільовий танк",
"description": "Останній танк для дослідження в гілці"
},
"starting_tank": {
"name": "початковий танк",
"description": "Початковий танк в гілці (виводиться автоматично, якщо не передбачено)"
}
},
"body": {
"subtitle": "Дослідження",
"total": "Загалом",
"research": "Дослідження: {cost}",
"upgrades": "Прокачування: {cost}",
"purchase": "Вартість: {cost}",
"equipment": "Спорядження: {cost}",
"estimation": "# Це оцінка!\n\nЦей список може включати вже досліджені танки через неточну інформацію для вантажу. Спробуйте використати \"початковий танк\" з рядка за допомогою команди."
},
"errors": {
"non_tech_tree": "#{tank} відсутній в дереві дослідження\n\nВи не можете дослідити преміум/колеційний танк.",
"tier_1": "#{tank} І рівня \n\nТанки І рівня завжди розблоковані для всіх гравців безкоштовно",
"already_researched": "# {tank} вже було досліджено\n\nСпробуйте використати `початковий-танк` коли використовуєте команду для перегляду загальної гілки, яку ви вже дослідили",
"start_end_equal": "#{tank} було введено двічі \n\nПереконайтесь що `початковий-танк` та `ціль-танк` різні",
"tanks_not_on_line": "# {tank_1} та {tank_2} не в одній гілці\n\nПереконайтесь що `початковий-танк` та `ціль-танк` знаходяться в єдиній гілці дерева дослідження",
"unordered": "# {tank_1} вище рівнем відносно {tank_2}\n\nОбов’язково вкажіть {tank_2} як `початковий-танк`, оскільки це танк нижчого рівня."
}
},
"about": {
"name": "про бота",
"description": "Вся інформація про бота",
"subcommands": {
"commands": {
"name": "команди",
"description": "Список всіх команд та їх описів",
"body": "# Команди\n\nBlitzKit пропонує наступні команди:\n\n"
},
"embeds": {
"name": "вкладення",
"description": "Як працюють вкладення"
},
"introduction": {
"name": "ознайомлення",
"description": "Про бота"
},
"invite": {
"name": "запрошення",
"description": "Як запросити бота"
},
"timezones": {
"name": "часові пояси",
"description": "Як BlitzKit отримує інформацію про час і використовує ваш часовий пояс"
},
"credits": {
"name": "кредити",
"description": "Люди, які допомогли BlitzKit"
}
}
},
"breakdown": {
"name": "аналіз",
"description": "Аналіз періоду за зіграними танками",
"body": {
"total": "Загалом",
"battles": "Бої",
"wn8": "WN8",
"winrate": "Відсоток перемог",
"damage": "Шкода",
"unknown_tank": "Невідомий танк {id}"
}
},
"debug": {
"name": "налагодження",
"description": "Інформація про налагодження бота",
"body": {
"title": "# Налагодження\n\n",
"version": "Версія",
"shard": {
"label": "Уламок",
"default": "за замовчуванням"
},
"uptime": "Час роботи"
}
},
"evolution": {
"name": "еволюція",
"description": "Еволюція статистики",
"groups": {
"player": {
"name": "гравець",
"description": "Статистика гравця"
},
"tank": {
"name": "танк",
"description": "Статистика танків"
}
}
},
"inactive": {
"name": "неактивний",
"description": "Відображає всіх неактивних гравців у клані вище порогу",
"options": {
"threshold": {
"name": "поріг",
"description": "Кількість днів неактивності (за замовчуванням: {days} днів)"
}
},
"body": {
"subtitle": "Неактивний {days}+ днів",
"listing": "{days} днів"
}
},
"full_stats": {
"name": "повна статистика",
"description": "Повна ігрова статистика",
"body": {
"cards": {
"games": {
"title": "Ігри",
"winrate": "Відсоток перемог",
"battles": "Бої",
"wins_losses": "Перемоги / поразки"
},
"efficiency": {
"title": "Ефективність",
"wn8": "WN8",
"survival": "Виживання",
"accuracy": "Точність"
},
"lethality": {
"title": "Летальність",
"average_damage": "Середня шкода",
"damage_per_tier": "Шкода за рівень",
"damage_ratio": "Коефіцієнт шкоди",
"average_kills": "Середня кількість знищень"
},
"miscellaneous": {
"title": "Різне",
"average_tier": "Середній рівень",
"average_spots": "Середній засвіт",
"average_xp": "Середній досвід",
"kills_to_death_ratio": "Співвідношення знищень до смертей"
}
}
}
},
"link": {
"name": "посилання",
"description": "Прив'язує ваш Blitz та Discord акаунт",
"body": {
"accounts_linked": "Прив'язані акаунти",
"no_role_permissions": {
"title": "{name} не вдалося перевірити",
"description": "У мене немає дозволу керувати ролями."
}
},
"embed": {
"title": "Невірний обліковий запис?",
"description": "Використайте команду ще раз і виберіть ім'я користувача з результатів пошуку."
}
},
"search_clans": {
"name": "пошук кланів",
"description": "Пошук кланів",
"options": {
"limit": {
"name": "ліміт",
"description": "Максимальна кількість результатів клану (за замовчуванням: {limit})"
}
},
"body": {
"title": "Пошук клану для {search} в регіоні {region}",
"no_results": "Жодного клану не знайдено"
}
},
"search_players": {
"name": "пошук гравців",
"description": "Пошук гравців",
"options": {
"limit": {
"name": "ліміт",
"description": "Максимальна кількість результатів гравця (за замовчуванням: {limit})"
}
},
"body": {
"title": "Пошук гравця для {search} у регіоні {region}",
"no_results": "Гравця не знайдено"
}
},
"rating_leaderboard": {
"name": "таблиця рейтингу",
"description": "Статистика рейтингових боїв",
"subcommands": {
"neighbors": {
"name": "сусіди",
"description": "Сусідуючі гравці в лідерборді"
},
"league": {
"name": "ліга",
"description": "Найкращий гравець ліги"
}
},
"options": {
"limit": {
"name": "ліміт",
"description": "Скільки сусідів відобразити (за замовчуванням: {count})"
},
"season": {
"name": "сезон",
"description": "Базова інформація про гравця",
"choices": {
"current": "{season} (поточний)"
}
},
"league": {
"name": "ліга",
"description": "Ліга для відображення"
}
},
"body": {
"top_players": "Топ {count} гравців",
"no_participation": "# {player} не грав у рейтингу в сезоні {season}\n\nЦей гравець не брав участь у цьому сезоні або не проходив калібрування",
"no_ongoing_season": "# Немає поточного сезону\n\nВ даний час немає сезону рейтингу.",
"deleted_player": "",
"neighbors": "Сусіди по рейтингу",
"more": "+ {count} ще"
}
},
"today": {
"name": "сьогодні",
"description": "Сьогодні зіграні танки та статистика"
},
"stats": {
"name": "статистика",
"description": "Коротка статистика за період"
},
"owned_tanks": {
"name": "отримані танки",
"description": "Показує всі ваші танки даного рівня",
"body": {
"title": "# {name} отриманих рівнів {tier} танків\n\n"
}
},
"permissions": {
"name": "дозволи",
"description": "Перевіряє чи бот має необхідні дозволи для роботи",
"body": {
"title": "# Дозволи\n\n{body}",
"view_channels": "Перегляньте канали: необхідне для знаходження повідомлення, на якому використовувалася кнопка оновлення",
"read_message_history": "Прочитайте історію повідомлень: потрібно знайти повідомлення для оновлення",
"attach_files": "Закріпіть файли: потрібно для додавання зображень до команд на основі зображень",
"external_emojis": "Зовнішні емодзі: потрібні для додавання емодзі національних прапорів та класів техніки"
}
},
"ping": {
"name": "",
"description": "Перевірити чи бот живий",
"body": {
"pong": "Понг🏓",
"pong_with_time": "Понг🏓 - {time}мс"
},
"subcommands": {
"blitzkit": {
"name": "BlitzKit",
"description": "Ping BlitzKit"
},
"wotb": {
"name": "WoTB",
"description": "Ping World of Tanks Blitz"
}
}
},
"player_info": {
"name": "інформація про гравця",
"description": "Базова інформація про гравця",
"body": {
"title": "інформація про {name}",
"nickname": "Нік",
"battles": "Бої",
"winrate": "Відсоток перемог",
"account_id": "ID акаунта",
"created": "Створено",
"last_battle": "Остання битва"
}
},
"rating": {
"name": "рейтинг",
"description": "Статистика рейтингових боїв гравця ",
"subcommands": {
"today": {
"name": "сьогодні",
"description": "Сьогоднішня статистика рейтингових боїв"
},
"season": {
"name": "сезон",
"description": "Статистика рейтингових боїв поточного сезону"
}
},
"body": {
"subtitle": {
"today": "Сьогоднішня статистика рейтингових боїв",
"season": "Статистика рейтингових боїв даного сезону"
}
},
"errors": {
"no_participation": "# {name} не грав рейтингові бої\n\nЦей гравець не брав участь у рейтинговому режимі цього сезону.",
"unrecorded_stats": "# Статистика на цей момент недоступна\n\nWargaming наразі зіткнулась з технічними несправностями. Якщо зараз проходить сезон, статистика буде доступною в найближчі 24 години."
}
}
}
},
"website": {
"redirect": {
"title": "301: переміщено назавжди",
@@ -660,7 +207,7 @@
},
"tank_search": {
"select_dialog_title": "Знайти танк",
"swap_dialog_title": "Swap tank",
"swap_dialog_title": "Резервуар підміни",
"clear_filters": "Очистити",
"login": "Увійдіть, щоб скористатися",
"search_bar_hint": "Шукайте техніку...",
@@ -671,8 +218,8 @@
"sorting_by": "Відсортувати за {name}",
"clear": "Clear",
"tier": "Рівень {tier}",
"passive": "{name} (Passive)",
"active": "{name} (Active)",
"passive": "",
"active": "{name}{name}",
"no_tanks_found": {
"body": "Нічого не знайдено.",
"search_again": "Спробуйте шукати заново.",
@@ -734,30 +281,22 @@
}
},
"home": {
"pwa": {
"title": "Install the BlitzKit App",
"new": "",
"checking": "Checking compatibility...",
"instructions": "Instructions for Apple devices.",
"install": "Install",
"dismiss": "Dismiss"
},
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
"join_short": "Приєднуйся до суспільства!",
"join_long": "Приєднуйся до найкрутішого суспільства!",
"action": "Discord"
},
"hero": {
"credit": "By {name} ❤️"
"credit": "Від {name} ❤️"
},
"hot_tanks": {
"title": "Популярні танки",
"subtitle": "Last {days} days"
"subtitle": "Останні {days} днів"
},
"other_projects": {
"title": "Інші класні проєкти"
},
"help_translate": "Please help translate {name} to {language}!",
"help_translate": "Будь ласка, допоможіть перекласти {name} на {language}!",
"seo_description": "Інструменти для всього, пов'язаного з WoT Blitz"
},
"docs": {
@@ -771,7 +310,7 @@
"reset": "Скинути",
"shuffle": "Перемішати",
"remove": "Видалити зіграні",
"tracking": "BlitzKit is tracking your battles",
"tracking": "BlitzKit відстежує ваші бої",
"sort": {
"button": "Сортувати за",
"last_played": "Остання гра",
@@ -797,15 +336,15 @@
"description": "Tank playlist generator",
"seo_description": "Don't know what to play in World of Tanks Blitz? Use BlitzKit Playlist to get suggestions!",
"button": "Створити",
"pool_size": "{count} possible tanks"
"pool_size": "{count} можливі танки"
},
"mixer": {
"name": "Mixer",
"button": "Mix and match",
"description": "Mix tank modules",
"seo_description": "Mix and match hulls, turrets, and guns of tanks in World of Tanks Blitz",
"screenshot": "Screenshot",
"randomize": "Randomize"
"screenshot": "Знімок екрану",
"randomize": "Рандомізувати"
},
"guess": {
"name": "Guess",
@@ -814,16 +353,16 @@
"seo_description": "Play a tank guessing game with a silhouette in World of Tanks Blitz",
"search": {
"placeholder": "Type to guess...",
"skip": "Skip",
"skip": "Пропустити",
"guess": "Guess",
"next": "Next",
"next": "Наступний",
"no_results": "Немає результатів"
},
"stats": "{correct} / {total} correct, {streak} streak",
"help": {
"title": "Partially reveal tank?",
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
"cancel": "Cancel",
"cancel": "",
"reveal": "Reveal"
},
"clear": "Clear",
@@ -831,7 +370,7 @@
"tier": "Рівень {tier}"
},
"tankopedia": {
"search": "Search a stat...",
"search": "Шукаємо стати...",
"name": "Танкопедія",
"button": "Знайти танки",
"description": "Танкова енциклопедія",
@@ -869,7 +408,7 @@
"yaw": "Yaw",
"pitch": "Pitch",
"min": "Min",
"max": "Max"
"max": "Макс"
}
},
"sandbox": {
@@ -901,8 +440,8 @@
"normalization": "Нормалізація",
"ricochet": "Рикошет",
"explosion_radius": "Радіус розльоту уламків",
"exit": "Exit",
"reset": "Reset"
"exit": "Вийти",
"reset": "Скинути"
},
"advanced": "Advanced highlighting",
"shot_card": {
@@ -911,17 +450,17 @@
"spaced": "Spaced",
"external": "External",
"gap": "Gap",
"gun": "Gun",
"track": "Tracks"
"gun": "Пушка",
"track": "Гусениці"
},
"status": {
"penetration": "{damage}hp penetration",
"blocked": "Blocked",
"penetration": "{damage} од. шкоди з пробиттям",
"blocked": "Заблоковано",
"ricochet": "Рикошет",
"splash": "{damage}hp splash"
"splash": "{damage} Од"
},
"stats": {
"thickness_and_angle": "{thickness}mm {angle}°",
"thickness_and_angle": "{thickness}мм {angle}°",
"nominal": "{thickness}mm nominal",
"ricochet_loss": "{loss}% penetration"
}
@@ -934,7 +473,7 @@
"external": "External",
"edit": {
"label": "Редагувати",
"reset": "Reset"
"reset": "Скинути"
}
}
},
@@ -947,12 +486,13 @@
},
"vanilla": "Vanilla",
"opentest": "Відкритий тест",
"full_name": "Full name",
"full_name": "Повна назва",
"nation": "Нація",
"class": "Клас",
"tier": "Рівень",
"type": "Вид",
"dev_id": "DEV: ID",
"dev_name": "DEV: NAME",
"purchase": "Purchase price",
"restoration": "Restoration price",
"sale": "Sale price",
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "Configuration",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "Beta"
},
"modules": {
"title": "Модулі",
"stock": "Stock",
@@ -1005,8 +550,8 @@
"title": "Characteristics",
"compare": {
"label": "Compare against",
"class": "Tier {tier} {class}",
"tier": "All of tier {tier}",
"class": "{tier} {class}",
"tier": "All tier {tier}",
"all": "Усі танки"
},
"values": {
@@ -1035,7 +580,7 @@
"caliber": "Калібр",
"penetration": "Бронепробиття",
"damage": "Шкода",
"damageWithoutAssault": "Damage without assault shells",
"damageWithoutAssault": "Шкода без урахування золотих снарядів",
"clipDamage": "Clipping potential",
"moduleDamage": "Шкода по модулях",
"explosionRadius": "Радіус розльоту уламків",
@@ -1044,7 +589,7 @@
"dispersion": "Нерухомо",
"dispersionMoving": "У русі",
"dispersionHullTraversing": "Hull traversing",
"dispersionTurretTraversing": "Turret traversing",
"dispersionTurretTraversing": "Обертання башти",
"dispersionShooting": "Shooting",
"dispersionGunDamaged": "Gun damaged",
"gunDepression": "Depression",
@@ -1073,7 +618,7 @@
"hullTraverseHardTerrain": "Hard",
"hullTraverseMediumTerrain": "Середній",
"hullTraverseSoftTerrain": "Soft",
"health": "Health",
"health": "Здоров'я",
"fireChance": "Fire chance",
"viewRange": "View range",
"camouflageStill": "Нерухомо",
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "Очистити",
"maximize": "Збільшити все"
"maximize": "Збільшити все",
"equalize": "Equalize"
},
"modules": {
"stock": "Stock",
@@ -1160,7 +706,7 @@
},
"performance": {
"name": "Performance",
"button": "View tanks",
"button": "Переглянути танки",
"description": "Tank performance statistics",
"seo_description": "Best tanks and their performances in World of Tanks Blitz",
"estimation": {
@@ -1197,10 +743,10 @@
"name": "Gallery",
"button": "Browse all",
"description": "Blitz player avatars",
"seo_description": "All World of Tanks Blitz player avatars",
"seo_description": "Усі World of Tanks Blitz аватари гравців",
"last_updated": "Last updated on {time}",
"search": {
"hint": "Search avatars...",
"hint": "Шукаємо аватари...",
"results": "{count} avatars"
}
},
@@ -1237,18 +783,18 @@
}
},
"tier_list": {
"name": "Tier list",
"button": "Rank tanks",
"description": "Rank Blitz tanks",
"name": "Список рівнів",
"button": "Ранги танків",
"description": "Ранги танків з блітзу",
"seo_description": "Explore tier lists ranking tanks from best to worst, based on player ratings and statistical performance in World of Tanks Blitz",
"buttons": {
"reset": "Reset",
"share": "Share"
"reset": "Скинути",
"share": "Поділитися"
}
},
"embed": {
"name": "Embed",
"button": "Create now",
"button": "Створити зараз",
"description": "Embeds for streaming",
"seo_description": "Create embeds for streaming World of Tanks Blitz with extreme customization",
"coming_soon": "More embeds coming soon.",
@@ -1259,22 +805,22 @@
},
"configuration": {
"import": {
"title": "Import",
"title": "Імпортувати",
"description": "Paste your current URL if you have one already to import your settings",
"hint": "Paste URL...",
"hint": "Вставити посилання...",
"apply": "Apply",
"idiot_title": "Invalid URL",
"idiot_title": "Некоректне посилання",
"idiot_description": "Try pasting the URL that BlitzKit previously generated, you silly goose!",
"idiot_button": "Okay, my bad"
},
"export": {
"title": "Export",
"title": "Експортувати",
"description": "Copy all properties for you streaming software",
"generate": {
"button": "Generate URL",
"title": "Generate URL",
"button": "Згенерувати посилання",
"title": "Генерація посилання",
"subtitle": "Search an account to track",
"cancel": "Cancel",
"cancel": "",
"success": {
"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\".",
@@ -1289,7 +835,7 @@
},
"customize": {
"title": "Customize",
"reset": "Reset",
"reset": "Скинути",
"description": "Bells and whistles of your embed"
}
},
@@ -1337,14 +883,14 @@
"seo_description": "Live and archived full rating leaderboard for World of Tanks Blitz"
},
"discord": {
"name": "Discord bot",
"button": "Install now",
"name": "Діскорд бот",
"button": "Встановити зараз",
"description": "Stats right in Discord",
"seo_description": "Get stats right in Discord with BlitzKit's Discord bot"
},
"more": {
"name": "More coming soon",
"button": "Join Discord",
"name": "Буде через певний час",
"button": "Приєднатись до Діскорду",
"description": "What we're making",
"seo_description": "What we're making with BlitzKit"
},
+65 -519
View File
@@ -13,18 +13,18 @@
"hp": "{value} 生命值",
"x": "x{value}",
"percentage": "{value}%",
"deg_s": "{value}度°/秒",
"deg_s": "{value}度每秒",
"plus": "+{value}"
},
"gun_types": {
"auto_loader": "弹夹型坦克",
"auto_reloader": "自动装填型坦克",
"auto_reloader": "弹鼓型坦克",
"regular": "单发"
},
"shells": {
"ap": "穿甲弹",
"ap_cr": "硬式复合穿甲弹",
"hc": "反战车高爆弹",
"hc": "破甲弹",
"he": "高爆弹"
},
"player_count_period": {
@@ -37,10 +37,11 @@
"d_1": "昨日"
},
"branches": {
"local": "开发者",
"dev": "测试版",
"beta": "测试版",
"development": "Development",
"opentest": "开放测试",
"preview": "预览"
"preview": "Preview",
"production": "Production"
},
"locales": {
"en": "英语",
@@ -60,23 +61,23 @@
"3": "平均",
"4": "高于平均",
"5": "好",
"6": "非常好",
"6": "好",
"7": "很好",
"8": "极品",
"9": "超级强势玩家"
"8": "非常好",
"9": "极品"
},
"bkni_percentile": {
"0": "Super malum",
"1": "Malum",
"2": "非常差",
"0": "垃圾",
"1": "非常差",
"2": "很差",
"3": "差",
"4": "低于平均",
"5": "平均",
"6": "高于平均",
"6": "较好",
"7": "好",
"8": "非常好",
"9": "極品",
"10": "超级强势玩家"
"8": "很好",
"9": "非常好",
"10": "极品"
},
"nations": {
"ussr": "苏联",
@@ -86,8 +87,8 @@
"uk": "英国",
"france": "法国",
"japan": "日本",
"european": "欧洲国家",
"other": "混合型国家"
"european": "欧盟 (E系)",
"other": "X系"
},
"nations_adjectives": {
"ussr": "苏联",
@@ -97,34 +98,34 @@
"uk": "英国",
"france": "法国",
"japan": "日本",
"european": "欧洲国家",
"other": "混合型国家"
"european": "欧盟 (E系)",
"other": "X系"
},
"tank_class_short": {
"-1": "未识别",
"-1": "未知",
"0": "轻型坦克",
"1": "中型坦克",
"2": "重型战车",
"3": "驱逐战车"
"3": "坦克歼击车"
},
"tank_class_short_plural_lowercase": {
"0": "轻型战车",
"1": "中型战车",
"2": "重型战车",
"3": "驱逐战车"
"0": "轻型坦克",
"1": "中型坦克",
"2": "重型坦克",
"3": "坦克歼击车"
},
"tank_class_medium": {
"-1": "未识别",
"0": "轻型战车",
"1": "中型战车",
"2": "重型战车",
"3": "驱逐战车"
"-1": "未知",
"0": "轻型坦克",
"1": "中型坦克",
"2": "重型坦克",
"3": "坦克歼击车"
},
"tree_type": {
"-1": "未识别",
"-1": "未知",
"0": "科技树",
"1": "加值战车",
"2": "收藏家战车"
"1": "金币车",
"2": "收藏车"
},
"regions": {
"normal": {
@@ -140,8 +141,8 @@
},
"leagues": {
"diamond": "钻石",
"platinum": "白金",
"gold": "黃金",
"platinum": "铂金",
"gold": "黄金",
"silver": "白银",
"bronze": "青铜"
},
@@ -156,7 +157,7 @@
"normalized_shots": "开火次数",
"normalized_spotted": "侦查次数",
"normalized_survived_battles": "存活率",
"normalized_win_and_survived": "存活胜利率",
"normalized_win_and_survived": "胜利并幸存的概率",
"normalized_wins": "胜率",
"normalized_xp": "经验值",
"normalized_battle_life_time": "战斗时间",
@@ -184,460 +185,6 @@
"cumulative_battle_life_time": "总战斗时间"
}
},
"bot": {
"common": {
"errors": {
"clan_not_found": "# 找不到公会\n找不到\"{search}\"。请尝试从搜索结果中选择一个公会。",
"player_not_found": "# 找不到玩家\n无法找到玩家 “{search}”。 尝试从搜索结果中选择玩家,或输入一个有效的玩家名称, 或使用“/link”命令。",
"player_not_linked": "# 使用 `/link` 来开始\n我不知道你是谁,但你今天可以告诉我!",
"tank_name_not_found": "# 找不到坦克\n找不到名为 “{search}” 的坦克。",
"tank_id_not_found": "# 找不到坦克\n无法找到ID为 “{search}” 的坦克。 请尝试输入坦克的名称而不是数字。",
"no_tank_stats": "# 没有这辆战车的数据\n这个玩家没有可用资料。 这可能不是你要找的玩家。",
"get_help": "Discord的协助服务器",
"uncaught_error": "# BlitzKit 发生错误!\n我们对此感到抱歉。 欢迎加入[官方Discord](https://discord.gg/nDt7AjGJQH),以方便帮助你解决问题。",
"preview": "# 此命令处于预览\n\n您只能在[官方Discord服务器](https://discord.gg/nDt7AjGJQH)访问此命令。该命令将很快可用。",
"query_too_small": "# 搜寻内容过短\n您的搜寻必需至少包含 3 个字元。",
"query_too_long": "# 搜索内容过长\n您搜索的内容必须少于 100 个字符。"
},
"wn8": {
"name": "WN8",
"types": {
"very_bad": "非常差",
"bad": "差",
"below_average": "低于平均",
"average": "平均",
"above_average": "高于平均",
"good": "好",
"very_good": "非常好",
"great": "很好",
"unicum": "極品",
"super_unicum": "超强势玩家"
}
},
"subcommands": {
"today": {
"name": "今日",
"description": "今日:"
},
"30": {
"name": "30",
"description": "30 天"
},
"60": {
"name": "60",
"description": "60 天"
},
"90": {
"name": "90",
"description": "90 天"
},
"career": {
"name": "生涯",
"description": "玩家资料"
},
"custom": {
"name": "自定义",
"description": "自定义范围",
"options": {
"start": {
"name": "开始",
"description": "距今若干天前开始"
},
"end": {
"name": "结束",
"description": "距今若干天前开结束"
}
}
}
},
"options": {
"clan": {
"name": "公会",
"description": "公会名称或标签"
},
"tank": {
"name": "战车",
"description": "要获取战绩的坦克"
},
"username": {
"name": "用户名",
"description": "玩家的闪击战游戏昵称"
},
"filters": {
"nation": {
"name": "国别",
"description": "国别"
},
"class": {
"name": "战车车型",
"description": "战车车型"
},
"type": {
"name": "战车类型",
"description": "战车类型"
}
},
"region": {
"name": "所在地区",
"description": "地区"
},
"tier": {
"name": "阶级",
"description": "阶级",
"choices": {
"tier": "{tier_1} - {tier_2} 阶"
}
}
},
"periods": {
"career": "玩家资料",
"today": "今日:",
"days": "{days} 天",
"custom": "{day_1} - {day_2} 天"
},
"filters": {
"none": "无筛选器",
"tier": "{tier} 阶"
},
"no_data": {
"battles_in_period": "在这段时间里没有参与任何战斗",
"battles_in_season": "在这个赛季中没有战斗记录",
"players_in_period": "这段时间内没有玩家",
"tanks_found": "找不到战车"
},
"buttons": {
"refresh": "刷新"
},
"hero_stats": {
"battles": "战斗场次",
"winrate": "胜率",
"damage": "伤害",
"damage_ratio": "伤害比",
"tier": "阶级",
"survival": "生存",
"accuracy": "命中率",
"kills": "击杀数"
}
},
"commands": {
"replay": {
"name": "回放",
"description": "显示重播结果"
},
"research": {
"name": "研发",
"description": "列出研发线路的费用",
"options": {
"target_tank": {
"name": "目标战车",
"description": "需要研发的目标(战车)"
},
"starting_tank": {
"name": "起始战车",
"description": "研发线路中的起始战车(如果未提供则自动推定)"
}
},
"body": {
"subtitle": "研发",
"total": "全部",
"research": "研发:{cost}",
"upgrades": "升级:{cost}",
"purchase": "购买:{cost}",
"equipment": "装备:{cost}",
"estimation": "# 这是一个估计值!\n\n这个列表可能包含已经研发过的战车,因为 Wargaming 提供了不正确的资料。 如果可以,请尝试在同一研发线路中提供一个 “起始战车” 。"
},
"errors": {
"non_tech_tree": "# \"{tank}\" 不在科技树里\n\n你不能研发一个 加值/收藏家 坦克。",
"tier_1": "# {tank} 是一级坦克\n\n一级坦克一直是对所有玩家免费解锁的。",
"already_researched": "# \"{tank}\" 已完成研发\n\n请尝试在同一研发线路上提供“起始坦克”, 以查看全部您已研发过的坦克。",
"start_end_equal": "# \"{tank}\" 重复提供了\n\n请确认 \"初始坦克\" 和 \"目标坦克\" 是不同的。",
"tanks_not_on_line": "# “{tank_1}” 和 “{tank_2}” 不在同一个研发线路上\n\n请确认“起始坦克” 和 “目标坦克” 在同一研发线路中。",
"unordered": "# “{tank_1}” 阶级比 “{tank_2}” 高\n\n请以提供 {tank_2} 作为起始坦克,因为它的阶级更低。"
}
},
"about": {
"name": "关于",
"description": "查看关于机器人的所有信息",
"subcommands": {
"commands": {
"name": "指令",
"description": "所有指令及其描述",
"body": "# 指令\n\nBlitzKit 提供了以下指令:\n\n"
},
"embeds": {
"name": "嵌入",
"description": "嵌入如何运作"
},
"introduction": {
"name": "介绍",
"description": "关于此机器人"
},
"invite": {
"name": "邀请",
"description": "如何邀请机器人"
},
"timezones": {
"name": "时区",
"description": "BlitzKit 如何判断并使用你的时区"
},
"credits": {
"name": "积分",
"description": "谁帮助过 BlitzKit"
}
}
},
"breakdown": {
"name": "详细分析",
"description": "在特定时期中, 战车的详细分析",
"body": {
"total": "全部",
"battles": "战斗场次",
"wn8": "WN8",
"winrate": "胜率",
"damage": "伤害",
"unknown_tank": "未知坦克 {id}"
}
},
"debug": {
"name": "侦错",
"description": "机器人侦错信息",
"body": {
"title": "# 侦错\n\n",
"version": "版本",
"shard": {
"label": "碎片",
"default": "默认"
},
"uptime": "运行时间"
}
},
"evolution": {
"name": "演变",
"description": "统计资料的演变",
"groups": {
"player": {
"name": "玩家",
"description": "玩家数据统计"
},
"tank": {
"name": "战车",
"description": "战车数据统计"
}
}
},
"inactive": {
"name": "不活跃",
"description": "列出公会中所有超过阈值的不活跃玩家",
"options": {
"threshold": {
"name": "阈值",
"description": "未上线天数( 默认:{days} 天)"
}
},
"body": {
"subtitle": "{days}+ 天未上线",
"listing": "{days} 天"
}
},
"full_stats": {
"name": "完整统计资料",
"description": "游戏内完整统计资料",
"body": {
"cards": {
"games": {
"title": "游戏",
"winrate": "胜率",
"battles": "战斗场次",
"wins_losses": "胜利/失败"
},
"efficiency": {
"title": "效率",
"wn8": "WN8",
"survival": "生存率",
"accuracy": "命中率"
},
"lethality": {
"title": "致命伤害",
"average_damage": "平均伤害",
"damage_per_tier": "各阶级伤害",
"damage_ratio": "伤害比",
"average_kills": "平均击毁"
},
"miscellaneous": {
"title": "杂项",
"average_tier": "平均阶级",
"average_spots": "平均侦查",
"average_xp": "平均经验",
"kills_to_death_ratio": "击杀阵亡比"
}
}
}
},
"link": {
"name": "链接",
"description": "链接您的 Blitz 和 Discord 账户",
"body": {
"accounts_linked": "帐号已绑定",
"no_role_permissions": {
"title": "{name} 验证失败",
"description": "我没有管理身份的权限。"
}
},
"embed": {
"title": "账户不正确?",
"description": "再次使用此命令,从搜索结果中选择一个用户名。"
}
},
"search_clans": {
"name": "搜寻-公会资料",
"description": "搜寻公会资料",
"options": {
"limit": {
"name": "限制",
"description": "公会结果的最大显示数量 (默认:{limit})"
}
},
"body": {
"title": "在地区 {region} 中搜索公会 {search}",
"no_results": "没有找到该公会"
}
},
"search_players": {
"name": "搜索-玩家",
"description": "搜索玩家",
"options": {
"limit": {
"name": "限制",
"description": "玩家结果的最大显示数量 (默认:{limit})"
}
},
"body": {
"title": "在地区 {region} 中搜索玩家 {search}",
"no_results": "未找到玩家"
}
},
"rating_leaderboard": {
"name": "评价战斗-排行榜",
"description": "评价战斗的统计数据",
"subcommands": {
"neighbors": {
"name": "附近的",
"description": "排行榜上附近的玩家"
},
"league": {
"name": "段位",
"description": "段位中的顶尖玩家"
}
},
"options": {
"limit": {
"name": "限制",
"description": "显示附近有多少玩家(默认:{count})"
},
"season": {
"name": "赛季",
"description": "赛季数 (默认:当前)",
"choices": {
"current": "{season} (当前)"
}
},
"league": {
"name": "段位",
"description": "要显示的段位"
}
},
"body": {
"top_players": "前 {count} 玩家",
"no_participation": "# {player} 没有在赛季 {season} 中进行过评价战斗\n\n该玩家没有参加该赛季或没有完成校准。",
"no_ongoing_season": "# 没有进行中的赛季\n\n目前没有赛季。",
"deleted_player": "已删除玩家 {id}",
"neighbors": "对邻居进行评分",
"more": "+ {count} 更多"
}
},
"today": {
"name": "今日",
"description": "今天玩过的战车和统计资料"
},
"stats": {
"name": "统计资料",
"description": "一段时间内的快速统计"
},
"owned_tanks": {
"name": "已拥有的战车",
"description": "显示该阶级中所有您已拥有的战车",
"body": {
"title": "# {name} 所拥有的 {tier} 阶坦克\n\n"
}
},
"permissions": {
"name": "权限",
"description": "检查机器人是否拥有运行所需的权限",
"body": {
"title": "# 权限\n\n{body}",
"view_channels": "查看频道:需要找到重新整理按钮使用的讯息",
"read_message_history": "读取消息历史: 需要找到消息以刷新",
"attach_files": "附加文件:需要将图像添加到基于图像的命令",
"external_emojis": "外部表情符号:需要添加国家旗帜和战车类别"
}
},
"ping": {
"name": "连接延迟",
"description": "检查机器人是否处于活动状态。",
"body": {
"pong": "Pong 🏓",
"pong_with_time": "Pong 🏓 - {time} 微秒"
},
"subcommands": {
"blitzkit": {
"name": "blitzkit",
"description": "测试BlitzKit的ping值(延迟值)"
},
"wotb": {
"name": "战车世界闪击战",
"description": "测试战车世界闪击战的ping值(延迟值)"
}
}
},
"player_info": {
"name": "玩家信息",
"description": "玩家基本信息",
"body": {
"title": "{name} 的信息",
"nickname": "昵称",
"battles": "战斗场次",
"winrate": "胜率",
"account_id": "账号ID",
"created": "创建时间",
"last_battle": "最后一场战斗"
}
},
"rating": {
"name": "评价战斗",
"description": "评价战斗的统计数据",
"subcommands": {
"today": {
"name": "今日",
"description": "今日评价战斗统计数据"
},
"season": {
"name": "赛季",
"description": "本季评价战斗统计数据"
}
},
"body": {
"subtitle": {
"today": "今日评价战斗统计数据",
"season": "本季评价战斗统计数据"
}
},
"errors": {
"no_participation": "# {name} 未曾游玩评价战斗\n\n该玩家未参与本赛季的评价战斗。",
"unrecorded_stats": "# 统计数据目前无法使用\n\nWargaming 可能暂停了服务器。 如果有连续的赛季,统计数据可能在24小时内提供。"
}
}
}
},
"website": {
"redirect": {
"title": "301: 已永久移动",
@@ -666,7 +213,7 @@
"search_bar_hint": "搜寻战车……",
"recent": "最近查看的",
"select_all": "全选",
"count_singular": "1辆战车",
"count_singular": "1 辆坦克",
"count_plural": "{count} 辆坦克",
"sorting_by": "按 {name} 排序",
"clear": "清除",
@@ -674,7 +221,7 @@
"passive": "{name} (被动)",
"active": "{name} (主动)",
"no_tanks_found": {
"body": "找不到战车。",
"body": "未找到坦克。",
"search_again": "请尝试重新搜索。",
"clear_filters": "请尝试清除筛选。"
},
@@ -688,11 +235,11 @@
"survivability.volume": "体积",
"survivability.length": "长度",
"fire.dpm": "标准炮弹 每分钟伤害血量",
"fire.dpmPremium": "加值炮弹 每分钟伤害血量",
"fire.dpmPremium": "金币炮弹 每分钟伤害值",
"fire.reload": "装填时间",
"fire.caliber": "口径",
"fire.standardPenetration": "标准炮弹穿透力",
"fire.premiumPenetration": "加值炮弹穿透力",
"fire.premiumPenetration": "金币炮弹穿透力",
"fire.tertiaryPenetration": "第三种炮弹穿透力",
"fire.damage": "炮弹伤害值",
"fire.moduleDamage": "模组伤害值",
@@ -734,17 +281,9 @@
}
},
"home": {
"pwa": {
"title": "安装 BlitzKit 应用程序",
"new": "新增",
"checking": "正在检查兼容性……",
"instructions": "Apple 设备的说明。",
"install": "安装",
"dismiss": "取消"
},
"discord": {
"join_short": "加入超級酷的人群!",
"join_long": "加入我們的Discord社群,和超酷的人一起聊天!",
"join_short": "加入超级酷的人群!",
"join_long": "加入我们的Discord社群,和超酷的人一起聊天!",
"action": "Discord"
},
"hero": {
@@ -758,7 +297,7 @@
"title": "其他酷炫的项目"
},
"help_translate": "请帮忙将 {name} 翻译成 {language}!",
"seo_description": "战车世界闪击战 全方位工具"
"seo_description": "坦克世界闪击战 全方位工具"
},
"docs": {
"patches": {
@@ -793,7 +332,7 @@
"proceed": "继续操作"
},
"generate": "创建游玩列表",
"name": "遊玩列表",
"name": "游玩列表",
"description": "坦克游玩列表生成器",
"seo_description": "想不到在坦克世界闪击战玩什么? 使用BlitzKit 游玩列表来获得建议!",
"button": "生成",
@@ -802,7 +341,7 @@
"mixer": {
"name": "组装",
"button": "混合搭配",
"description": "混合坦克模块",
"description": "混搭不同坦克间的模块",
"seo_description": "《坦克世界:闪击战》的车体, 炮塔, 主炮混合搭配",
"screenshot": "屏幕截图",
"randomize": "随机搭配"
@@ -953,8 +492,9 @@
"tier": "阶级",
"type": "战车类型",
"dev_id": "开发参数:ID",
"dev_name": "DEV: NAME",
"purchase": "购买价格",
"restoration": "恢复战车价格",
"restoration": "恢复坦克价格",
"sale": "出售价格",
"research": "研发所需经验"
},
@@ -973,6 +513,11 @@
},
"configuration": {
"title": "配置设定",
"equalizer": {
"title": "Equalizer",
"equalize": "Equalize",
"beta": "测试版"
},
"modules": {
"title": "坦克模块",
"stock": "白板",
@@ -1005,8 +550,8 @@
"title": "属性",
"compare": {
"label": "比较",
"class": "{tier}阶 {class}",
"tier": "所有 {tier} 阶",
"class": "{tier} 阶的 {class}",
"tier": "所有{tier} 阶的",
"all": "所有坦克"
},
"values": {
@@ -1049,10 +594,10 @@
"dispersionGunDamaged": "主炮损坏时",
"gunDepression": "俯角",
"gunElevation": "仰角",
"gunFrontalDepression": "车辆前部俯角",
"gunFrontalElevation": "车辆前部仰角",
"gunRearDepression": "车辆後部俯角",
"gunRearElevation": "车辆後部仰角",
"gunFrontalDepression": "车体前部俯角",
"gunFrontalElevation": "车体前部仰角",
"gunRearDepression": "车体后部俯角",
"gunRearElevation": "车体后部仰角",
"azimuthLeft": "左射界",
"azimuthRight": "右射界",
"speedForwards": "最高前进速度",
@@ -1089,8 +634,8 @@
"shellCapacity": "携弹量",
"gunType": "炮管类型",
"penetrationAt250m": "两百五十米处的穿透力",
"burstShells": "Burst shell count",
"burstInterShell": "Burst inter-shell"
"burstShells": "爆破计数",
"burstInterShell": "爆破弹"
}
},
"firepower": {
@@ -1142,7 +687,8 @@
},
"skills": {
"clear": "清除",
"maximize": "最大化"
"maximize": "最大化",
"equalize": "平衡"
},
"modules": {
"stock": "白板",
@@ -1252,7 +798,7 @@
"description": "用于串流的嵌入",
"seo_description": "创建具有极高自订化的《坦克世界:闪击战》串流嵌入功能",
"coming_soon": "更多嵌入功能即将推出。",
"suggest": "建议与想法",
"suggest": "建议与想法。",
"preview": {
"title": "示例预览",
"upload": "上传测试背景"
-1
View File
@@ -24,7 +24,6 @@
"fast-xml-parser": "^5.2.5",
"googleapis": "^162.0.0",
"lodash-es": "^4.17.21",
"lz4js": "^0.2.0",
"progress": "^2.0.3",
"puppeteer": "^24.22.3",
"sharp": "^0.34.4",
+36 -21
View File
@@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises";
import { parse as parsePath } from "path";
import ProgressBar from "progress";
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
import { vfs } from "./buildAssets/constants";
import { PATCHES_ROOT, vfs } from "./buildAssets/constants";
import { writeDVPL } from "./core/blitz/writeDVPL";
const versionTextFile = await vfs.text(`Data/version.txt`);
@@ -20,27 +20,30 @@ let patchIndex = 1;
while (true) {
const response = await fetch(
`${assertSecret(
import.meta.env.WOTB_DLC_CDN
)}/dlc/s${currentVersion}_${patchIndex}.yaml`
import.meta.env.WOTB_DLC_CDN,
)}/dlc/s${currentVersion}_${patchIndex}.yaml`,
);
if (response.status === 200) {
console.log(patchIndex, response.status)
if (!response.ok) break;
console.log(`Applying patch ${patchIndex}...`);
const data = parseYaml(await response.text());
const dvpm = await fetch(
`${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11}`
`${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11}`,
).then((response) => response.arrayBuffer());
const dvpd = await fetch(
`${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11.replace(
".dvpm",
".dvpd"
)}`
".dvpd",
)}`,
).then((response) => response.arrayBuffer());
const files = await dvp(dvpm, dvpd);
const bar = new ProgressBar(
`Patching ${files.length} files :bar`,
files.length
files.length,
);
for (const { path, data } of files) {
@@ -49,43 +52,55 @@ while (true) {
const { dir } = parsePath(path);
try {
await mkdir(`Data/${dir}`, { recursive: true });
await mkdir(`${PATCHES_ROOT}/Data/${dir}`, { recursive: true });
} catch (error) {
console.warn(`Failed to make directory "${dir}"`);
}
const isDvpl = path.endsWith(".dvpl");
const buffer = Buffer.from(data);
await writeFile(
`Data/${path}${isDvpl ? "" : ".dvpl"}`,
new Uint8Array(isDvpl ? buffer : writeDVPL(buffer))
`${PATCHES_ROOT}/Data/${path}`,
new Uint8Array(buffer),
);
bar.tick();
}
if ("dynamicContentLocalizationsDir" in data) {
console.log("Found dynamic content localizations; patching...");
console.log('patches done for patch')
if ("dynamicContentLocalizationsDir" in data) {
console.log(
`${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${
data.dynamicContentLocalizationsDir
}/en.yaml`,
);
const localizationsResponse = await fetch(
`${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${
data.dynamicContentLocalizationsDir
}/en.yaml`
}/en.yaml`,
);
console.log('fetched')
const newStrings = parseYaml(await localizationsResponse.text());
const oldStrings = await vfs.yaml<Record<string, string>>(
`Data/Strings/en.yaml`
);
console.log('got new strings')
const oldStrings =
await vfs.yaml<Record<string, string>>(`Data/Strings/en.yaml`);
console.log('got old strings')
const patchedStrings = { ...oldStrings, ...newStrings };
const patchedContent = stringifyYaml(patchedStrings);
console.log('stringified')
await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true });
console.log('mkdir')
await writeFile(
`Data/Strings/en.yaml`,
new Uint8Array(writeDVPL(Buffer.from(patchedContent)))
`${PATCHES_ROOT}/Data/Strings/en.yaml`,
new Uint8Array((Buffer.from(patchedContent))),
);
console.log('file')
}
patchIndex++;
} else break;
}
vfs.dispose()
process.exit(0);
+23 -20
View File
@@ -1,5 +1,6 @@
import {
AverageDefinitions,
AverageDefinitionsAllStats,
AverageDefinitionsEntry,
type AverageDefinitionsManifest,
type IndividualTankStats,
@@ -30,9 +31,6 @@ type OptionalSecondLevel<T> = {
};
};
type AverageDefinitionsEntrySubPartial =
OptionalSecondLevel<AverageDefinitionsEntry>;
const MINUTE = 60 * 1000;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
@@ -47,15 +45,15 @@ const preDiscoveredIds = await fetchPreDiscoveredIds();
const playerIds: Record<Region, number[][]> = {
asia: chunk(
preDiscoveredIds.filter((id) => idToRegion(id) === "asia"),
PLAYER_IDS_PER_CALL
PLAYER_IDS_PER_CALL,
),
com: chunk(
preDiscoveredIds.filter((id) => idToRegion(id) === "com"),
PLAYER_IDS_PER_CALL
PLAYER_IDS_PER_CALL,
),
eu: chunk(
preDiscoveredIds.filter((id) => idToRegion(id) === "eu"),
PLAYER_IDS_PER_CALL
PLAYER_IDS_PER_CALL,
),
};
let regionIndex = 0;
@@ -71,7 +69,7 @@ times(THREADS, async () => {
const regionIds = playerIds[region];
const [ids] = regionIds.splice(
Math.floor(Math.random() * regionIds.length),
1
1,
);
const accountInfo = await getAccountInfo(region, ids, undefined, {
fields: "last_battle_time,statistics.all.battles",
@@ -104,8 +102,8 @@ times(THREADS, async () => {
filteredIds.map((id) =>
getTankStats(region, id, {
fields: "last_battle_time,battle_life_time,all,tank_id",
})
)
}),
),
);
players.forEach((tanks) => {
@@ -114,7 +112,7 @@ times(THREADS, async () => {
if (!tankIds.includes(tank.tank_id)) {
console.log(
`Found new tank: ${tank.tank_id} (${tankIds.length + 1})`
`Found new tank: ${tank.tank_id} (${tankIds.length + 1})`,
);
tankIds.push(tank.tank_id);
tanksSorted[tank.tank_id] = [];
@@ -140,7 +138,7 @@ async function postWork() {
console.log(
`Generating statistics based on ${samples.d_120.toLocaleString()} players (${samples.total.toLocaleString()} checked in total) and ${
tankIds.length
} tanks...`
} tanks...`,
);
using uploader = new AssetUploader("averages");
@@ -152,7 +150,12 @@ async function postWork() {
// (tank) => Date.now() - tank.last_battle_time * 1000 <= MAX_ACTIVITY_TIME,
// );
const tanks = tanksSortedEntry;
const entry: AverageDefinitionsEntrySubPartial = {
const entry: {
mu: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
sigma: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
r: Partial<Record<keyof AverageDefinitionsAllStats, number>>;
samples: Samples;
} = {
mu: {},
sigma: {},
r: {},
@@ -162,13 +165,13 @@ async function postWork() {
tanks.forEach((tank) => {
const timeSinceLastActivity = Date.now() - tank.last_battle_time * 1000;
entry.samples.total++;
if (timeSinceLastActivity <= 120 * DAY) entry.samples.d_120++;
if (timeSinceLastActivity <= 90 * DAY) entry.samples.d_90++;
if (timeSinceLastActivity <= 60 * DAY) entry.samples.d_60++;
if (timeSinceLastActivity <= 30 * DAY) entry.samples.d_30++;
if (timeSinceLastActivity <= 7 * DAY) entry.samples.d_7++;
if (timeSinceLastActivity <= 1 * DAY) entry.samples.d_1++;
entry.samples!.total++;
if (timeSinceLastActivity <= 120 * DAY) entry.samples!.d_120++;
if (timeSinceLastActivity <= 90 * DAY) entry.samples!.d_90++;
if (timeSinceLastActivity <= 60 * DAY) entry.samples!.d_60++;
if (timeSinceLastActivity <= 30 * DAY) entry.samples!.d_30++;
if (timeSinceLastActivity <= 7 * DAY) entry.samples!.d_7++;
if (timeSinceLastActivity <= 1 * DAY) entry.samples!.d_1++;
});
const dataWY = tanks.map((tank) => ({
@@ -191,7 +194,7 @@ async function postWork() {
function sum(slicer: (data: DataPoint) => number) {
return data.reduce(
(accumulator, data) => accumulator + slicer(data),
0
0,
);
}
@@ -6,13 +6,15 @@ export async function boosterIcons() {
console.log("Building booster icons...");
const uploader = new AssetUploader("booster icons");
const boosterFiles = vfs
const boosterFiles = await vfs
.dir("Data/Gfx/Shared/boosters")
.filter(
(file) => !file.includes("@2x.txt") && !file.startsWith("texture0")
.then((files) =>
files.filter(
(file) => !file.includes("@2x.txt") && !file.startsWith("texture0"),
),
);
const image = sharp(
await vfs.file(`Data/Gfx/Shared/boosters/texture0.packed.webp`)
await vfs.file(`Data/Gfx/Shared/boosters/texture0.packed.webp`),
);
for (const file of boosterFiles) {
@@ -6,7 +6,7 @@ export async function camouflageIcons() {
using uploader = new AssetUploader("camo icons");
const content = await vfs.file(
`Data/Gfx/UI/Hangar/IconCamouflage.packed.webp`
`Data/Gfx/UI/Hangar/IconCamouflage.packed.webp`,
);
await uploader.add({ content, path: "icons/camo.webp" });
+11 -1
View File
@@ -1,10 +1,15 @@
import { assertSecret } from "@blitzkit/core";
import { AbstractVFS } from "../core/vfs/abstract";
import { LocalVFS } from "../core/vfs/local";
import { SteamVFS } from "../core/vfs/steam";
import { ZipVFS } from "../core/vfs/zip";
import { MixedVFS } from "../core/vfs/mixed";
export const PATCHES_ROOT = "../../temp/patches";
const steamPattern = /steam:(\d+)\/(\d+)/;
const zipPattern = /zip:(.+)/;
const localePattern = /local:"?(.+)"?/;
const source = Bun.argv
.find((arg) => arg.startsWith("--source="))
@@ -21,13 +26,18 @@ if (!source) {
assertSecret(import.meta.env.STEAM_USERNAME),
assertSecret(import.meta.env.STEAM_PASSWORD),
app,
depot
depot,
).init();
} else if (zipPattern.test(source)) {
const [, url] = source.match(zipPattern)!;
resolved = await new ZipVFS(url).init();
} else if (localePattern.test(source)) {
const [, path] = source.match(localePattern)!;
resolved = await new LocalVFS(path).init();
} else {
throw new Error("No valid source specified");
}
resolved = new MixedVFS([new LocalVFS(PATCHES_ROOT), resolved]);
export const vfs = resolved;
@@ -1,5 +1,6 @@
import sharp from "sharp";
import { AssetUploader } from "../core/github/assetUploader";
import { parsePackedSpriteRect } from "../core/blitz/parsePackedSpriteRect";
import { vfs } from "./constants";
import { ConsumablesCommon, ProvisionsCommon } from "./definitions";
@@ -13,31 +14,61 @@ interface Mappings {
const listItemsPattern = /<items path="(.+)\.xml"\/>/g;
async function extractPackedIcon(
texture: sharp.Sharp,
sizes: number[],
context: string,
) {
const [left, top, width, height] = sizes;
const bounds = [left, top, width, height];
if (!bounds.every(Number.isInteger)) {
throw new Error(
`Invalid RIFF sprite bounds for ${context}: ${bounds.join(" ")}`,
);
}
const metadata = await texture.metadata();
if (metadata.width === undefined || metadata.height === undefined) {
throw new Error(`Failed to read image dimensions for ${context}`);
}
if (
left < 0 ||
top < 0 ||
width <= 0 ||
height <= 0 ||
left + width > metadata.width ||
top + height > metadata.height
) {
throw new Error(
`Out-of-bounds RIFF sprite for ${context}: ${bounds.join(" ")} in ${metadata.width}x${metadata.height}`,
);
}
return await texture.clone().extract({ left, top, width, height }).toBuffer();
}
export async function consumableProvisionIcons() {
console.log("Building consumable and provision icons...");
using uploader = new AssetUploader("consumable and provision icons");
const styles = [
"UI/Styles/Lobby/Inventory/InventoryNormalStyles.yaml",
"UI/Styles/Lobby/Inventory/Event/InventoryBigStyles.yaml",
"UI/Styles/Lobby/Inventory/Event/InventoryNormalStyles.yaml",
"UI/Styles/Lobby/Inventory/InventoryNormalStyles.yaml",
"UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml",
"UI/Screens/Battle/Styles/BattleEquipmentStyles.yaml",
];
const styleSheets = await Promise.all(
styles.map(async (path) =>
Object.values(
(
await vfs.yaml<Mappings>(`Data/${path}`)
).StyleSheets
)
)
Object.values((await vfs.yaml<Mappings>(`Data/${path}`)).StyleSheets),
),
).then((array) => array.flat());
for (const match of (
await vfs.text(
`Data/XML/item_defs/vehicles/common/consumables/list.xml`
)
await vfs.text(`Data/XML/item_defs/vehicles/common/consumables/list.xml`)
).matchAll(listItemsPattern)) {
const consumablesCommon = await vfs.xml<{
root: ConsumablesCommon;
@@ -46,13 +77,13 @@ export async function consumableProvisionIcons() {
for (const consumable of Object.values(consumablesCommon.root)) {
const styleSheet = styleSheets.find((styleSheet) =>
styleSheet.selectors.some((selector) =>
selector.includes(`${consumable.icon} `)
)
selector.includes(`${consumable.icon} `),
),
);
if (!styleSheet) {
console.warn(
`No style sheet found for consumable ${consumable.icon}; skipping...`
`No style sheet found for consumable ${consumable.icon}; skipping...`,
);
continue;
}
@@ -62,11 +93,21 @@ export async function consumableProvisionIcons() {
.replace(".psd", "")
.replace(".txt", "");
if (vfs.resolve(`Data/${configPath}.packed.webp`)) {
const image = sharp(
await vfs.file(`Data/${configPath}.packed.webp`)
);
const content = await image.trim({ threshold: 100 }).toBuffer();
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
const packedBuffer = await vfs.file(`Data/${configPath}.packed.webp`);
const consumablesTexture = sharp(packedBuffer);
const sizes = parsePackedSpriteRect(packedBuffer);
let content: Buffer;
if (sizes) {
content = await extractPackedIcon(
consumablesTexture,
sizes,
`consumable ${consumable.icon}`,
);
} else {
content = await consumablesTexture.trim({ threshold: 80 }).toBuffer();
}
await uploader.add({
path: `icons/consumables/${consumable.id}.webp`,
@@ -78,8 +119,8 @@ export async function consumableProvisionIcons() {
`${`Data/${configPath}`
.split("/")
.slice(0, -1)
.join("/")}/texture0.packed.webp`
)
.join("/")}/texture0.packed.webp`,
),
);
const sizes = (await vfs.text(`Data/${configPath}.txt`))
.split("\n")[4]
@@ -104,9 +145,7 @@ export async function consumableProvisionIcons() {
}
for (const match of (
await vfs.text(
`Data/XML/item_defs/vehicles/common/provisions/list.xml`
)
await vfs.text(`Data/XML/item_defs/vehicles/common/provisions/list.xml`)
).matchAll(listItemsPattern)) {
const provisionsCommon = await vfs.xml<{
root: ProvisionsCommon;
@@ -115,13 +154,13 @@ export async function consumableProvisionIcons() {
for (const provision of Object.values(provisionsCommon.root)) {
const styleSheet = styleSheets.find((styleSheet) =>
styleSheet.selectors.some((selector) =>
selector.includes(`${provision.icon} `)
)
selector.includes(`${provision.icon} `),
),
);
if (!styleSheet) {
console.warn(
`No style sheet found for provision ${provision.icon}; skipping...`
`No style sheet found for provision ${provision.icon}; skipping...`,
);
continue;
}
@@ -131,11 +170,21 @@ export async function consumableProvisionIcons() {
.replace(".psd", "")
.replace(".txt", "");
if (vfs.resolve(`Data/${configPath}.packed.webp`)) {
const image = sharp(
await vfs.file(`Data/${configPath}.packed.webp`)
);
const content = await image.trim({ threshold: 100 }).toBuffer();
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
const packedBuffer = await vfs.file(`Data/${configPath}.packed.webp`);
const provisionsTexture = sharp(packedBuffer);
const sizes = parsePackedSpriteRect(packedBuffer);
let content: Buffer;
if (sizes) {
content = await extractPackedIcon(
provisionsTexture,
sizes,
`provision ${provision.icon}`,
);
} else {
content = await provisionsTexture.trim({ threshold: 80 }).toBuffer();
}
await uploader.add({
path: `icons/provisions/${provision.id}.webp`,
@@ -147,8 +196,8 @@ export async function consumableProvisionIcons() {
`${`Data/${configPath}`
.split("/")
.slice(0, -1)
.join("/")}/texture0.packed.webp`
)
.join("/")}/texture0.packed.webp`,
),
);
const sizes = (await vfs.text(`Data/${configPath}.txt`))
.split("\n")[4]
@@ -20,7 +20,7 @@ export async function currencies() {
for (const [file, name] of ICONS) {
const content = await sharp(
await vfs.file(`Data/Gfx/Lobby/currency/${file}`)
await vfs.file(`Data/Gfx/Lobby/currency/${file}`),
)
.trim()
.toBuffer();
@@ -36,14 +36,14 @@ export async function currencies() {
.then((glossary) =>
Object.values(glossary)
.entries()
.filter(([key]) => /^prx_season_\d+$/.test(`${key}`))
.filter(([key]) => /^prx_season_\d+$/.test(`${key}`)),
);
for (const [key, item] of glossary) {
if (item.image_url === null) throw new Error(`No image_url for ${key}`);
const imageRaw = await fetch(item.image_url).then((response) =>
response.arrayBuffer()
response.arrayBuffer(),
);
const content = await sharp(imageRaw)
.trim({
+155 -122
View File
@@ -8,6 +8,7 @@ import {
ConsumableTankCategoryFilterCategory,
Crew,
CrewType,
Equalizer,
EquipmentDefinitions,
EquipmentSlot,
GameDefinitions,
@@ -32,6 +33,7 @@ import {
} from "@blitzkit/core";
import { SUPPORTED_LOCALE_BLITZ_MAP } from "@blitzkit/i18n";
import locales from "@blitzkit/i18n/locales.json";
import { readFile } from "fs/promises";
import { deburr } from "lodash-es";
import { parse as parsePath } from "path";
import type { Vector3Tuple } from "three";
@@ -81,16 +83,16 @@ const blitzTankFilterDefinitionCategoryToBlitzkit: Record<
BlitzTankFilterDefinitionCategory,
ConsumableTankCategoryFilterCategory
> = {
clip: ConsumableTankCategoryFilterCategory.CLIP,
clip: ConsumableTankCategoryFilterCategory.CONSUMABLE_TANK_CATEGORY_FILTER_CATEGORY_CLIP,
};
function vector3TupleToBlitzkit(tuple: Vector3Tuple) {
return { x: tuple[0], y: tuple[1], z: tuple[2] } satisfies Vector3;
}
const blitzTankClassToBlitzkit: Record<BlitzTankClass, TankClass> = {
lightTank: TankClass.LIGHT,
"AT-SPG": TankClass.TANK_DESTROYER,
heavyTank: TankClass.HEAVY,
mediumTank: TankClass.MEDIUM,
lightTank: TankClass.TANK_CLASS_LIGHT,
"AT-SPG": TankClass.TANK_CLASS_TANK_DESTROYER,
heavyTank: TankClass.TANK_CLASS_HEAVY,
mediumTank: TankClass.TANK_CLASS_MEDIUM,
};
export interface BlitzStrings {
[key: string]: string;
@@ -135,7 +137,7 @@ export interface ChassisDefinitionsList {
}
type VehicleDefinitionArmor = Record<
string,
number | { vehicleDamageFactor: 0; "#text": number }
number | { vehicleDamageFactor: 0; "#text": number } | number[]
>;
interface UnlocksInner {
cost: number | string;
@@ -149,18 +151,18 @@ type BlitzModuleType = {
type UnlocksListing = BlitzModuleType | undefined;
type BlitzCrewType = "commander" | "radioman" | "gunner" | "driver" | "loader";
const blitzCrewTypeToBlitzkit: Record<BlitzCrewType, CrewType> = {
commander: CrewType.COMMANDER,
driver: CrewType.DRIVER,
gunner: CrewType.GUNNER,
loader: CrewType.LOADER,
radioman: CrewType.RADIOMAN,
commander: CrewType.CREW_TYPE_COMMANDER,
driver: CrewType.CREW_TYPE_DRIVER,
gunner: CrewType.CREW_TYPE_GUNNER,
loader: CrewType.CREW_TYPE_LOADER,
radioman: CrewType.CREW_TYPE_RADIOMAN,
};
const blitzkitCrewTypeToBlitz: Record<CrewType, BlitzCrewType> = {
[CrewType.COMMANDER]: "commander",
[CrewType.DRIVER]: "driver",
[CrewType.GUNNER]: "gunner",
[CrewType.LOADER]: "loader",
[CrewType.RADIOMAN]: "radioman",
[CrewType.CREW_TYPE_COMMANDER]: "commander",
[CrewType.CREW_TYPE_DRIVER]: "driver",
[CrewType.CREW_TYPE_GUNNER]: "gunner",
[CrewType.CREW_TYPE_LOADER]: "loader",
[CrewType.CREW_TYPE_RADIOMAN]: "radioman",
};
interface VehicleDefinitions {
invisibility: {
@@ -298,7 +300,7 @@ interface VehicleDefinitions {
type: "default";
enabled: false;
factorsModifiers: "";
}
},
];
};
};
@@ -517,20 +519,36 @@ type CombatRolesYaml = Record<
>;
const blitzShellKindToBlitzkit: Record<ShellKind, ShellType> = {
ARMOR_PIERCING: ShellType.AP,
ARMOR_PIERCING_CR: ShellType.APCR,
HIGH_EXPLOSIVE: ShellType.HE,
HOLLOW_CHARGE: ShellType.HEAT,
ARMOR_PIERCING: ShellType.SHELL_TYPE_AP,
ARMOR_PIERCING_CR: ShellType.SHELL_TYPE_APCR,
HIGH_EXPLOSIVE: ShellType.SHELL_TYPE_HE,
HOLLOW_CHARGE: ShellType.SHELL_TYPE_HEAT,
};
export const botPattern = /^.+((tutorial_bot(\d+)?)|(TU))$/;
const blitzModuleTypeToBlitzkit: Record<keyof BlitzModuleType, ModuleType> = {
chassis: ModuleType.TRACKS,
engine: ModuleType.ENGINE,
gun: ModuleType.GUN,
turret: ModuleType.TURRET,
vehicle: ModuleType.VEHICLE,
chassis: ModuleType.MODULE_TYPE_TRACKS,
engine: ModuleType.MODULE_TYPE_ENGINE,
gun: ModuleType.MODULE_TYPE_GUN,
turret: ModuleType.MODULE_TYPE_TURRET,
vehicle: ModuleType.MODULE_TYPE_VEHICLE,
};
function assignArmor(
raw: VehicleDefinitionArmor[string],
id: number,
armor: Armor,
) {
if (typeof raw === "number") {
armor.thickness[id] = raw;
} else if (Array.isArray(raw)) {
armor.thickness[id] = raw.at(-1)!;
} else {
if (!armor.spaced) armor.spaced = [];
armor.thickness[id] = raw["#text"];
armor.spaced.push(id);
}
}
export async function definitions() {
console.log("Building definitions...");
@@ -555,18 +573,18 @@ export async function definitions() {
const provisionDefinitions: ProvisionDefinitions = { provisions: {} };
const skillDefinitions: SkillDefinitions = {
classes: {
[TankClass.LIGHT]: { skills: [] },
[TankClass.MEDIUM]: { skills: [] },
[TankClass.HEAVY]: { skills: [] },
[TankClass.TANK_DESTROYER]: { skills: [] },
[TankClass.TANK_CLASS_LIGHT]: { skills: [] },
[TankClass.TANK_CLASS_MEDIUM]: { skills: [] },
[TankClass.TANK_CLASS_HEAVY]: { skills: [] },
[TankClass.TANK_CLASS_TANK_DESTROYER]: { skills: [] },
},
};
const nations = vfs
const nations = await vfs
.dir("Data/XML/item_defs/vehicles")
.filter((nation) => nation !== "common");
.then((files) => files.filter((nation) => nation !== "common"));
const tankStringIdMap: Record<string, number> = {};
const optionalDevices = await vfs.xml<{ root: OptionalDevices }>(
"Data/XML/item_defs/vehicles/common/optional_devices.xml"
"Data/XML/item_defs/vehicles/common/optional_devices.xml",
);
const stringsI18n: Record<string, Record<string, string>> = {};
@@ -574,12 +592,12 @@ export async function definitions() {
locales.supported.map(async ({ locale }) => {
const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale];
const cache = await fetch(
`https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`
`https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`,
)
.then((response) => response.text())
.then((string) => parseYaml(string) as BlitzStrings);
const preInstalled = await vfs.yaml<BlitzStrings>(
`Data/Strings/${blitzLocale}.yaml`
`Data/Strings/${blitzLocale}.yaml`,
);
stringsI18n[locale] = {
@@ -588,7 +606,7 @@ export async function definitions() {
};
console.log(`Loaded strings for ${locale}`);
})
}),
);
function getString(name: string) {
@@ -627,9 +645,9 @@ export async function definitions() {
consumables,
(
await vfs.xml<{ root: ConsumablesCommon }>(
`Data/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`
`Data/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`,
)
).root
).root,
);
}
@@ -642,39 +660,57 @@ export async function definitions() {
provisions,
(
await vfs.xml<{ root: ConsumablesCommon }>(
`Data/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`
`Data/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`,
)
).root
).root,
);
}
const avatar = await vfs.xml<{ root: Avatar }>(
`Data/XML/item_defs/tankmen/avatar.xml`
`Data/XML/item_defs/tankmen/avatar.xml`,
);
const maps = await vfs.yaml<Maps>(`Data/maps.yaml`);
const tankXps = new Map<number, ResearchCost>();
const camouflagesXml = await vfs.xml<{ root: CamouflagesXML }>(
`Data/XML/item_defs/vehicles/common/camouflages.xml`
`Data/XML/item_defs/vehicles/common/camouflages.xml`,
);
const camouflagesYaml = await vfs.yaml<CamouflagesYaml>(
`Data/camouflages.yaml`
`Data/camouflages.yaml`,
);
const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages);
const squadBattleTypeStyles = await vfs.yaml<SquadBattleTypeStyles>(
`Data/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`
`Data/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`,
);
const gameTypeSelectorStyles = await vfs.yaml<SquadBattleTypeStyles>(
`Data/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`
`Data/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`,
);
const gameModeNativeNames: Record<string, number> = {};
const combatRoles = await vfs.yaml<CombatRolesYaml>(
`Data/XML/item_defs/vehicles/common/combat_roles.yaml`
`Data/XML/item_defs/vehicles/common/combat_roles.yaml`,
);
const consumableNativeNames: Record<string, number> = {};
const provisionNativeNames: Record<string, number> = {};
let equalizerDefinitions: string[][];
if (
await vfs.resolve("Data/XML/item_defs/vehicles/common/tier_equializer.csv")
) {
equalizerDefinitions = await vfs.csv(
`Data/XML/item_defs/vehicles/common/tier_equializer.csv`,
{ delimiter: ";" },
);
} else {
const stubEqualizerDefinitions = await readFile("stub/equalizer.csv").then(
(buffer) => buffer.toString(),
);
equalizerDefinitions = await vfs._csv(stubEqualizerDefinitions, {
delimiter: ";",
});
}
for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll(
/"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g
/"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g,
)) {
const id = Number(match[1]);
const name = getString(match[2]);
@@ -686,7 +722,7 @@ export async function definitions() {
}
for (const match of gameTypeSelectorStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll(
/eGameMode\.([a-zA-Z]+) -> "~res:\/Gfx\/UI\/Hangar\/GameTypes\/battle-type_([^"]+)"/g
/eGameMode\.([a-zA-Z]+) -> "~res:\/Gfx\/UI\/Hangar\/GameTypes\/battle-type_([^"]+)"/g,
)) {
Object.entries(gameModeNativeNames).forEach(([key, value]) => {
if (key.toLowerCase() === match[2].toLowerCase()) {
@@ -720,7 +756,7 @@ export async function definitions() {
for (const nation of nations) {
const tankList = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
);
for (const tankKey in tankList.root) {
@@ -761,7 +797,7 @@ export async function definitions() {
console.warn(
`Multiple tanks share slug ${slug}: ${requesters
.map(({ key }) => key)
.join(", ")}`
.join(", ")}`,
);
if (requesters.length !== 2) {
@@ -791,7 +827,7 @@ export async function definitions() {
if (canonical === undefined) {
throw new Error(
"Two tutorial bots share the same slug? The world is truly broken."
"Two tutorial bots share the same slug? The world is truly broken.",
);
}
@@ -804,7 +840,7 @@ export async function definitions() {
for (const nation of nations) {
const tankList = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
);
const turretList = await vfs.xml<{
root: TurretDefinitionsList;
@@ -857,7 +893,7 @@ export async function definitions() {
: Number(item.cost.split(":")[1]),
},
} satisfies Unlock;
})
}),
)
.flat();
}
@@ -872,10 +908,10 @@ export async function definitions() {
const tank = tankList.root[tankKey];
let tankPrice: TankPrice;
const tankDefinition = await vfs.xml<{ root: VehicleDefinitions }>(
`Data/XML/item_defs/vehicles/${nation}/${tankKey}.xml`
`Data/XML/item_defs/vehicles/${nation}/${tankKey}.xml`,
);
const tankParameters = await vfs.yaml<TankParameters>(
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
);
const turretOrigin = tankDefinition.root.hull.turretPositions.turret
.split(" ")
@@ -890,23 +926,23 @@ export async function definitions() {
if (slug === undefined) {
throw new Error(
`Could not find slug for ${nation}/${tankKey} (${tankId})`
`Could not find slug for ${nation}/${tankKey} (${tankId})`,
);
}
if (tank.sellPrice) {
tankPrice = {
type: TankPriceType.GOLD,
type: TankPriceType.TANK_PRICE_TYPE_GOLD,
value: tank.sellPrice["#text"] * 2,
};
} else if (typeof tank.price === "number") {
tankPrice = {
type: TankPriceType.CREDITS,
type: TankPriceType.TANK_PRICE_TYPE_CREDITS,
value: tank.price,
};
} else {
tankPrice = {
type: TankPriceType.CREDITS,
type: TankPriceType.TANK_PRICE_TYPE_CREDITS,
value: tank.price["#text"] * 400,
};
}
@@ -923,13 +959,7 @@ export async function definitions() {
const armorId = parseInt(armorIdString);
const armorRaw = tankDefinition.root.hull.armor[name];
if (typeof armorRaw === "number") {
hullArmor.thickness[armorId] = armorRaw;
} else {
if (!hullArmor.spaced) hullArmor.spaced = [];
hullArmor.thickness[armorId] = armorRaw["#text"];
hullArmor.spaced.push(armorId);
}
assignArmor(armorRaw, armorId, hullArmor);
});
const crew: Crew[] = [];
const fixedCamouflage = tankTags.includes("eventCamouflage_user");
@@ -938,7 +968,7 @@ export async function definitions() {
Object.entries(tankDefinition.root.crew).forEach(([crewKey, value]) => {
let entry: Crew;
const index = crew.findIndex(
({ type }) => blitzkitCrewTypeToBlitz[type] === crewKey
({ type }) => blitzkitCrewTypeToBlitz[type] === crewKey,
);
if (index === -1) {
if (crewKey === "#text") return;
@@ -988,10 +1018,23 @@ export async function definitions() {
})
.map(([, camo]) => camo.id);
let equalizerEntry = equalizerDefinitions.find(
(line) => line[0] === `${nation}:${tankKey}`,
);
let equalizer: Equalizer | undefined;
if (equalizerEntry) {
const [health, penetration, module_health, damage, armor] =
equalizerEntry?.slice(1).map(Number);
equalizer = { health, penetration, module_health, damage, armor };
}
tankDefinitions.tanks[tankId] = {
ancestors: [],
successors: [],
id: tankId,
dev_name: tankKey,
roles: {},
camouflages: camouflages,
fixed_camouflage: fixedCamouflage,
@@ -1011,10 +1054,10 @@ export async function definitions() {
slug,
nation,
type: tankTags.includes("collectible")
? TankType.COLLECTOR
? TankType.TANK_TYPE_COLLECTOR
: (typeof tank.price === "number" ? false : "gold" in tank.price)
? TankType.PREMIUM
: TankType.RESEARCHABLE,
? TankType.TANK_TYPE_PREMIUM
: TankType.TANK_TYPE_RESEARCHABLE,
tier: tank.level,
class: blitzTankClassToBlitzkit[tankTags[0] as BlitzTankClass],
testing: tankTags.includes("testTank"),
@@ -1022,21 +1065,22 @@ export async function definitions() {
price: tankPrice,
camouflage_still: tankDefinition.root.invisibility.still,
camouflage_moving: tankDefinition.root.invisibility.moving,
camouflage_onFire: tankDefinition.root.invisibility.firePenalty,
camouflage_on_fire: tankDefinition.root.invisibility.firePenalty,
turrets: [],
engines: [],
tracks: [],
equalizer,
};
if (tank.combatRole) {
Object.entries(tank.combatRole).forEach(([gameMode, role]) => {
const id = Object.entries(gameModeNativeNames).find(
([key]) => key.toLowerCase() === gameMode.toLowerCase()
([key]) => key.toLowerCase() === gameMode.toLowerCase(),
)?.[1];
if (id === undefined) {
throw new Error(
`Unknown game mode in tank ${tankKey}: ${gameMode}`
`Unknown game mode in tank ${tankKey}: ${gameMode}`,
);
}
@@ -1118,7 +1162,7 @@ export async function definitions() {
(turretKey, turretIndex) => {
const turret = tankDefinition.root.turrets0[turretKey];
const turretModel = Number(
parsePath(turret.models.undamaged).name.split("_")[1]
parsePath(turret.models.undamaged).name.split("_")[1],
);
const turretId = toUniqueId(nation, turretList.root.ids[turretKey]);
const turretYaw = (
@@ -1150,13 +1194,7 @@ export async function definitions() {
const armorId = parseInt(armorIdString);
const armorRaw = turret.armor[name];
if (typeof armorRaw === "number") {
turretArmor.thickness[armorId] = armorRaw;
} else {
if (!turretArmor.spaced) turretArmor.spaced = [];
turretArmor.thickness[armorId] = armorRaw["#text"];
turretArmor.spaced.push(armorId);
}
assignArmor(armorRaw, armorId, turretArmor);
});
turret.userString;
@@ -1186,12 +1224,12 @@ export async function definitions() {
min: vector3TupleToBlitzkit(
tankParameters.collision[
parsePath(turret.hitTester.collisionModel).name.toLowerCase()
].bbox.min
].bbox.min,
),
max: vector3TupleToBlitzkit(
tankParameters.collision[
parsePath(turret.hitTester.collisionModel).name.toLowerCase()
].bbox.max
].bbox.max,
),
},
};
@@ -1209,7 +1247,7 @@ export async function definitions() {
.split(" ")
.map(Number) as [number, number];
const gunModel = Number(
parsePath(gun.models.undamaged).name.split("_")[1]
parsePath(gun.models.undamaged).name.split("_")[1],
);
const gunName = getString(gunListEntry.userString);
const gunType =
@@ -1287,13 +1325,8 @@ export async function definitions() {
}
const armorId = parseInt(armorIdString);
const armorRaw = gun.armor[name];
if (typeof armorRaw === "number") {
gunArmor.thickness[armorId] = armorRaw;
} else {
if (!gunArmor.spaced) gunArmor.spaced = [];
gunArmor.thickness[armorId] = armorRaw["#text"];
gunArmor.spaced.push(armorId);
}
assignArmor(armorRaw, armorId, gunArmor);
});
tankDefinitions.tanks[tankId].turrets[turretIndex].guns.push({
@@ -1332,24 +1365,24 @@ export async function definitions() {
},
}
: gunType === "autoReloader"
? {
$case: "auto_reloader",
value: {
intra_clip: 60 / gun.clip!.rate,
shell_count: gunClipCount,
shell_reloads: gun
.pumpGunReloadTimes!.split(" ")
.map(Number),
? {
$case: "auto_reloader",
value: {
intra_clip: 60 / gun.clip!.rate,
shell_count: gunClipCount,
shell_reloads: gun
.pumpGunReloadTimes!.split(" ")
.map(Number),
},
}
: {
$case: "auto_loader",
value: {
intra_clip: 60 / gun.clip!.rate,
clip_reload: gun.reloadTime,
shell_count: gunClipCount,
},
},
}
: {
$case: "auto_loader",
value: {
intra_clip: 60 / gun.clip!.rate,
clip_reload: gun.reloadTime,
shell_count: gunClipCount,
},
},
} satisfies GunDefinition);
modelDefinitions.models[tankId].turrets[turretId].guns[gunId] = {
@@ -1360,8 +1393,8 @@ export async function definitions() {
gun.armor.gun === undefined
? 0
: typeof gun.armor.gun === "number"
? gun.armor.gun
: gun.armor.gun["#text"],
? gun.armor.gun
: gun.armor.gun["#text"],
pitch: {
min: gunPitch[0],
max: gunPitch[1],
@@ -1408,7 +1441,7 @@ export async function definitions() {
type: blitzShellKindToBlitzkit[shell.kind],
explosion_radius:
shell.kind === "HIGH_EXPLOSIVE"
? shell.explosionRadius ?? 0
? (shell.explosionRadius ?? 0)
: undefined,
icon: shell.icon,
penetration: {
@@ -1419,7 +1452,7 @@ export async function definitions() {
});
});
});
}
},
);
totalUnlocks.forEach((unlocks) => {
@@ -1447,7 +1480,7 @@ export async function definitions() {
case "gun": {
gunXps.set(
toUniqueId(nation, gunList.root.ids[vehicle["#text"]]),
parseResearchCost(vehicle.cost)
parseResearchCost(vehicle.cost),
);
break;
}
@@ -1455,7 +1488,7 @@ export async function definitions() {
case "turret": {
turretXps.set(
toUniqueId(nation, turretList.root.ids[vehicle["#text"]]),
parseResearchCost(vehicle.cost)
parseResearchCost(vehicle.cost),
);
break;
}
@@ -1463,7 +1496,7 @@ export async function definitions() {
case "engine": {
engineXps.set(
toUniqueId(nation, enginesList.root.ids[vehicle["#text"]]),
parseResearchCost(vehicle.cost)
parseResearchCost(vehicle.cost),
);
break;
}
@@ -1471,7 +1504,7 @@ export async function definitions() {
case "chassis": {
trackXps.set(
toUniqueId(nation, chassisList.root.ids[vehicle["#text"]]),
parseResearchCost(vehicle.cost)
parseResearchCost(vehicle.cost),
);
break;
}
@@ -1518,7 +1551,7 @@ export async function definitions() {
name: getString(optionalDeviceEntry.userString),
description: getString(optionalDeviceEntry.description),
};
}
},
);
Object.entries(optionalDeviceSlots.root.presets).forEach(
@@ -1537,7 +1570,7 @@ export async function definitions() {
})
.flat(),
};
}
},
);
Object.entries(consumables).forEach(([key, consumable]) => {
@@ -1620,7 +1653,7 @@ export async function definitions() {
(item) =>
blitzTankFilterDefinitionCategoryToBlitzkit[
item as BlitzTankFilterDefinitionCategory
]
],
),
},
},
@@ -1718,7 +1751,7 @@ export async function definitions() {
(item) =>
blitzTankFilterDefinitionCategoryToBlitzkit[
item as BlitzTankFilterDefinitionCategory
]
],
),
},
},
@@ -1749,11 +1782,11 @@ export async function definitions() {
value.default_abilities.forEach((ability) => {
if (ability in consumableNativeNames) {
gameDefinitions.roles[value.id].consumables.push(
consumableNativeNames[ability]
consumableNativeNames[ability],
);
} else if (ability in provisionNativeNames) {
gameDefinitions.roles[value.id].provisions.push(
provisionNativeNames[ability]
provisionNativeNames[ability],
);
} else throw new Error(`Unknown ability ${ability}`);
});
@@ -17,15 +17,15 @@ export async function equipmentIcons() {
using uploader = new AssetUploader("equipment icons");
const optionalDevices = await vfs.xml<{ root: OptionalDevices }>(
`Data/XML/item_defs/vehicles/common/optional_devices.xml`
`Data/XML/item_defs/vehicles/common/optional_devices.xml`,
);
const mappings = await vfs.yaml<Mappings>(
`Data/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`
`Data/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`,
);
const image = sharp(
await vfs.file(
`Data/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`
)
`Data/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`,
),
);
for (const optionalDeviceKey in optionalDevices.root) {
@@ -35,8 +35,8 @@ export async function equipmentIcons() {
const mapping = mappings.StyleSheets.find((mapping) =>
mapping.selectors.includes(
`.optional_device_item.${optionalDevice.icon} #Img`
)
`.optional_device_item.${optionalDevice.icon} #Img`,
),
);
if (!mapping) {
@@ -49,9 +49,7 @@ export async function equipmentIcons() {
if (configPath.startsWith("Gfx/Lobby")) {
const configPathWebp = configPath.replace(".txt", "");
const image = sharp(
await vfs.file(`Data/${configPathWebp}.packed.webp`)
);
const image = sharp(await vfs.file(`Data/${configPathWebp}.packed.webp`));
const content = await image.trim().toBuffer();
await uploader.add({
+24 -14
View File
@@ -6,20 +6,32 @@ export async function flags() {
console.log("Building flags...");
using uploader = new AssetUploader("flags");
const circleFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
(flag) =>
flag.startsWith("flag_profile-stat_") &&
!flag.endsWith("@2x.packed.webp")
const circleFiles = await vfs
.dir(`Data/Gfx/Lobby/flags`)
.then((files) =>
files.filter(
(flag) =>
flag.startsWith("flag_profile-stat_") &&
!flag.endsWith("@2x.packed.webp"),
),
);
const scratchedFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
const scratchedFiles = await vfs
.dir(`Data/Gfx/Lobby/flags`)
.then((files) =>
files.filter(
(flag) =>
flag.startsWith("flag_tutor-tank_") &&
!flag.endsWith("@2x.packed.webp")
)
const fadedFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
(flag) =>
flag.startsWith("flag_filter_") && flag.endsWith("@2x.packed.webp")
)
!flag.endsWith("@2x.packed.webp"),
),
);
const fadedFiles = await vfs
.dir(`Data/Gfx/Lobby/flags`)
.then((files) =>
files.filter(
(flag) =>
flag.startsWith("flag_filter_") && flag.endsWith("@2x.packed.webp"),
),
);
for (const flag of circleFiles) {
const image = sharp(await vfs.file(`Data/Gfx/Lobby/flags/${flag}`));
@@ -43,9 +55,7 @@ export async function flags() {
}
for (const flag of fadedFiles) {
const content = await sharp(
await vfs.file(`Data/Gfx/Lobby/flags/${flag}`)
)
const content = await sharp(await vfs.file(`Data/Gfx/Lobby/flags/${flag}`))
.trim({
threshold: 100,
background: { r: 0, g: 0, b: 0, alpha: 0 },
Loaded 100 of 223 files, more files were not shown because too many files have changed in this diff. Show more