mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ef355c574 | ||
|
|
71e1ab1362 | ||
|
|
53dc108356 | ||
|
|
57b3218c5a | ||
|
|
7472e39faf | ||
|
|
034417d19f | ||
|
|
0368e9ceda | ||
|
|
28f365f762 | ||
|
|
40a81f6b1b | ||
|
|
9475d22472 | ||
|
|
9538a03afb | ||
|
|
d5d171bea6 | ||
|
|
a9c9a90ac1 | ||
|
|
f7c562f8b6 | ||
|
|
836cf69f01 | ||
|
|
ba17aae706 | ||
|
|
30ca5c053a | ||
|
|
c36419f5b6 | ||
|
|
1879895db2 | ||
|
|
c964e3c8ec | ||
|
|
2ef6d18f82 | ||
|
|
10b672572b | ||
|
|
2a4efa8cd2 | ||
|
|
5a8435da29 | ||
|
|
3461349a96 | ||
|
|
3791e9df12 | ||
|
|
b3c36aac93 | ||
|
|
c0895409bc | ||
|
|
438b565cbb | ||
|
|
cf1a82e89b | ||
|
|
0506e361b2 | ||
|
|
d6a1357a82 | ||
|
|
a5a1dbd51b | ||
|
|
5201350e44 | ||
|
|
6a84b9d5ae | ||
|
|
cf04fe21b3 | ||
|
|
84eb3c2da3 | ||
|
|
22bf2dc1d8 | ||
|
|
b9c339daa7 | ||
|
|
ef3006cac1 | ||
|
|
e482fd40c1 | ||
|
|
cc4569966e | ||
|
|
3708a3ced7 | ||
|
|
0ae59c2fd7 | ||
|
|
7027f63236 | ||
|
|
6725e79021 | ||
|
|
5ca3cee9da | ||
|
|
602a5a1e99 | ||
|
|
bfbf3bdc39 | ||
|
|
644686582e | ||
|
|
1c00bc81f8 | ||
|
|
ac3b69bec5 | ||
|
|
3e14c943b6 | ||
|
|
d33633be2c | ||
|
|
4bf70d02d0 | ||
|
|
377bcf0e38 | ||
|
|
884b6d4318 |
No files matched your search
@@ -39,6 +39,17 @@ env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
||||
PUBLIC_DEBUG_MISSING_I18N: false
|
||||
|
||||
jobs:
|
||||
download_client:
|
||||
@@ -106,6 +117,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
@@ -127,7 +141,7 @@ jobs:
|
||||
|
||||
- name: Start server and build assets
|
||||
run: |
|
||||
bun dev:website &
|
||||
bun dev:website --verbosepa &
|
||||
SERVER_PID=$!
|
||||
|
||||
bun run build:assets --all-targets --depot --production
|
||||
|
||||
@@ -2,7 +2,6 @@ name: Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: main
|
||||
workflow_dispatch:
|
||||
|
||||
schedule:
|
||||
@@ -27,6 +26,8 @@ env:
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -53,6 +54,7 @@ jobs:
|
||||
path: dist/website
|
||||
|
||||
deploy-github-pages:
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
|
||||
@@ -27,3 +27,4 @@ target
|
||||
/.vercel
|
||||
/.astro
|
||||
.vercel
|
||||
/src
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
files:
|
||||
- source: /packages/core/lang/en.json
|
||||
- source: /packages/i18n/strings/en.json
|
||||
translation: /%original_path%/%locale%.json
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.1
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a crash that occurs if tanks are deleted in Blitz and were once available in BlitzKit
|
||||
- All tank icons are now back
|
||||
- The tank search once again returns results
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.2
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Fixes
|
||||
|
||||
- The new Improved Vertical Stabilizer equipment which only affects the gun depression found on the Type 63 now works
|
||||
@@ -0,0 +1,9 @@
|
||||
# BlitzKit 1.27.3
|
||||
|
||||
This update only affects the bot.
|
||||
|
||||
## Fixes
|
||||
|
||||
- Added support for 64-bit IDs allowing users with new accounts to link with BlitzKit
|
||||
- This comes at the added cost of resetting the links of all other accounts
|
||||
- Just re-link and you're good to go
|
||||
@@ -0,0 +1,3 @@
|
||||
# FreakKit 1.27.4
|
||||
|
||||
It has come to our attention that tanks are very harsh objects. To even it out, we made the website a pretty pretty princess <3
|
||||
@@ -0,0 +1,11 @@
|
||||
# BlitzKit 1.27.5
|
||||
|
||||
This update only affects the bot.
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed `/auction`
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a bug that caused `/rating` to disappear
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"private": true,
|
||||
"version": "1.27.0",
|
||||
"version": "1.27.5",
|
||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||
"type": "module",
|
||||
"types": "./types.d.ts",
|
||||
@@ -35,7 +35,8 @@
|
||||
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||
"preview:website": "cd packages/website && bun run preview",
|
||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||
"build:ids": "cd packages/scripts && bun build:ids"
|
||||
"build:ids": "cd packages/scripts && bun build:ids",
|
||||
"prunestrings": "cd packages/scripts && bun prunestrings"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -17,7 +17,7 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const list = [
|
||||
[strings.bot.commands.debug.body.version, packageJSON.version],
|
||||
[
|
||||
strings.bot.commands.debug.body.shard,
|
||||
strings.bot.commands.debug.body.shard.label,
|
||||
client.shard?.ids[0] ?? strings.bot.commands.debug.body.shard.default,
|
||||
],
|
||||
[
|
||||
|
||||
@@ -16,8 +16,8 @@ export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
||||
gap: 16,
|
||||
width: '100%',
|
||||
color: theme.colors.textHighContrast,
|
||||
backgroundColor: theme.colors.appBackground1,
|
||||
position: 'relative',
|
||||
background: theme.colors.appBackground1,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { SEARCH_KEYS } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
@@ -19,10 +20,7 @@ export async function resolveTankId(
|
||||
const searchResult = go(
|
||||
`${tank}`,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
limit: 1,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 1 },
|
||||
);
|
||||
|
||||
if (searchResult.length === 0) {
|
||||
|
||||
@@ -8,12 +8,12 @@ export async function filtersToDescription(
|
||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { strings } = translator(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;
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name.locales[bkLocale];
|
||||
if (nation)
|
||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||
if (tier) {
|
||||
|
||||
@@ -8,6 +8,8 @@ export async function getBlitzFromDiscord(discordId: bigint) {
|
||||
|
||||
if (unique === null) return null;
|
||||
|
||||
await flagUserActivity(unique.blitz_id);
|
||||
return { id: unique.blitz_id, region: idToRegion(unique.blitz_id) };
|
||||
const id = Number(unique.blitz_id);
|
||||
|
||||
await flagUserActivity(id);
|
||||
return { id, region: idToRegion(id) };
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { fetchTankNames, TankType } from '@blitzkit/core';
|
||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
|
||||
import {
|
||||
ApplicationCommandOptionChoiceData,
|
||||
AutocompleteInteraction,
|
||||
@@ -32,16 +31,7 @@ export async function autocompleteTanks(
|
||||
go(
|
||||
focusedOption.value,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: [
|
||||
...SUPPORTED_LOCALES.map((locale) => [
|
||||
`searchableName.{locale}`,
|
||||
`searchableNameDeburr.{locale}`,
|
||||
]).flat(),
|
||||
'camouflages',
|
||||
],
|
||||
limit: 10,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 10 },
|
||||
).map(async (item) => {
|
||||
let name = unwrap(item.obj.searchableName);
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ import { Locale } from 'discord.js';
|
||||
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
|
||||
import { translator } from '../localization/translator';
|
||||
|
||||
const validNameRegex = /^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/u;
|
||||
const validNameRegex =
|
||||
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
||||
|
||||
export function localizationObject(
|
||||
path: (strings: BlitzKitStrings) => string,
|
||||
@@ -14,7 +15,8 @@ export function localizationObject(
|
||||
(localizations, locale) => {
|
||||
const { strings } = translator(locale);
|
||||
const translation = literalsFunc(path(strings), literals);
|
||||
const isValid = !strict || validNameRegex.test(translation);
|
||||
const isValid =
|
||||
(!strict || validNameRegex.test(translation)) && translation.length > 0;
|
||||
|
||||
if (!isValid) {
|
||||
console.warn(
|
||||
|
||||
File renamed without changes.
@@ -12,8 +12,9 @@ export function translator(localeRaw: Locale) {
|
||||
SUPPORTED_LOCALES_DISCORD.includes(localeRaw)
|
||||
? localeRaw
|
||||
: DEFAULT_LOCALE_DISCORD;
|
||||
const strings = STRINGS[SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]];
|
||||
const unwrap = unwrapper(SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]);
|
||||
const bkLocale = SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale];
|
||||
const strings = STRINGS[bkLocale];
|
||||
const unwrap = unwrapper(bkLocale);
|
||||
|
||||
return { locale, strings, unwrap };
|
||||
return { locale, strings, unwrap, bkLocale };
|
||||
}
|
||||
@@ -19,11 +19,11 @@ import { Writeable } from '../../../types/writable';
|
||||
export async function handleChatInputCommand(
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const awaitedCommands = await commands;
|
||||
const registry = awaitedCommands[interaction.commandName];
|
||||
|
||||
await interaction.deferReply();
|
||||
|
||||
try {
|
||||
const returnable = await registry.handler(interaction);
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
SlashCommandSubcommandsOnlyBuilder,
|
||||
} from 'discord.js';
|
||||
import { aboutCommand } from '../../commands/about';
|
||||
import { auctionCommand } from '../../commands/auction';
|
||||
import { breakdownCommand } from '../../commands/breakdown';
|
||||
import { debugCommand } from '../../commands/debug';
|
||||
import { evolutionCommand } from '../../commands/evolution';
|
||||
@@ -80,7 +79,7 @@ interface CommandRegistryExplicit extends CommandRegistryBase {
|
||||
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
||||
|
||||
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
||||
auctionCommand,
|
||||
// auctionCommand,
|
||||
permissionsCommand,
|
||||
debugCommand,
|
||||
aboutCommand,
|
||||
|
||||
@@ -45,7 +45,7 @@ const interval = setInterval(async () => {
|
||||
const usernames = awaitedDiscoveredIdsDefinitions.count;
|
||||
|
||||
manager.broadcastEval(
|
||||
(client, { servers, users, channels, tanks, usernames }) => {
|
||||
async (client, { servers, users, channels, tanks, usernames }) => {
|
||||
const bios = [
|
||||
`Living in ${servers.toLocaleString()} servers`,
|
||||
`Serving ${users.toLocaleString()} users`,
|
||||
@@ -62,6 +62,13 @@ const interval = setInterval(async () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for (const guild of client.guilds.cache.values()) {
|
||||
try {
|
||||
const botMember = await guild.members.fetch(client.user.id);
|
||||
await botMember.setNickname('BlitzKit');
|
||||
} catch {}
|
||||
}
|
||||
},
|
||||
{ context: { servers, channels, users, tanks, usernames } },
|
||||
);
|
||||
|
||||
@@ -18,12 +18,27 @@ import {
|
||||
} from '@radix-ui/colors';
|
||||
import { createBorderStyles, createColors, createSpaces } from 'bepaint';
|
||||
|
||||
const funnyColors = {
|
||||
pink1: crimsonDark.crimson5,
|
||||
pink2: crimsonDark.crimson5,
|
||||
pink3: crimsonDark.crimson5,
|
||||
pink4: crimsonDark.crimson6,
|
||||
pink5: crimsonDark.crimson6,
|
||||
pink6: crimsonDark.crimson7,
|
||||
pink7: crimsonDark.crimson7,
|
||||
pink8: crimsonDark.crimson8,
|
||||
pink9: crimsonDark.crimson9,
|
||||
pink10: crimsonDark.crimson10,
|
||||
pink11: crimsonDark.crimson11,
|
||||
pink12: crimsonDark.crimson12,
|
||||
};
|
||||
|
||||
// this isn't really a stitches config, but the object is compliant
|
||||
export const theme = {
|
||||
spaces: createSpaces(),
|
||||
|
||||
colors: {
|
||||
...createColors(slateDark),
|
||||
...createColors(funnyColors),
|
||||
...createColors(slateDarkA, 'alpha'),
|
||||
...createColors(slate, 'light'),
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { deburr } from 'lodash-es';
|
||||
import { SUPPORTED_LOCALES } from '../../../i18n/src/strings';
|
||||
import { I18nString } from '../protos';
|
||||
import { fetchCamouflageDefinitions } from './camouflageDefinitions';
|
||||
import { fetchTankDefinitions } from './tankDefinitions';
|
||||
@@ -25,11 +26,21 @@ export async function fetchTankNames() {
|
||||
searchableName: tank.name_full ?? tank.name,
|
||||
searchableNameDeburr,
|
||||
camouflages: tank.camouflages
|
||||
?.map((id) => camouflageDefinitions.camouflages[id]?.name)
|
||||
?.map((id) => SUPPORTED_LOCALES.map((locale) => camouflageDefinitions.camouflages[id]?.name.locales[locale]))
|
||||
.flat()
|
||||
.filter(Boolean)
|
||||
.map(deburr)
|
||||
.join(' '),
|
||||
treeType: tank.type,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export const SEARCH_KEYS = [
|
||||
...SUPPORTED_LOCALES.map((locale) => [
|
||||
`searchableName.locales.${locale}`,
|
||||
`searchableNameDeburr.locales.${locale}`,
|
||||
]).flat(),
|
||||
'camouflages',
|
||||
];
|
||||
+750
-81
File diff suppressed because it is too large.
Load diff
+965
-296
File diff suppressed because it is too large.
Load diff
+831
-162
File diff suppressed because it is too large.
Load diff
+945
-276
File diff suppressed because it is too large.
Load diff
+921
-252
File diff suppressed because it is too large.
Load diff
+787
-118
File diff suppressed because it is too large.
Load diff
+980
-311
File diff suppressed because it is too large.
Load diff
+996
-327
File diff suppressed because it is too large.
Load diff
@@ -10,7 +10,8 @@
|
||||
"build:reviews": "bun src/reviews.ts",
|
||||
"build:ids": "bun src/discoverIds.ts",
|
||||
"build:bot": "bun src/buildBot.ts",
|
||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts"
|
||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
|
||||
"prunestrings": "bun src/pruneStrings.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzkit/core": "workspace:*",
|
||||
|
||||
@@ -45,19 +45,27 @@ while (true) {
|
||||
files.length,
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
files.map(async ({ path, data }) => {
|
||||
const { dir } = parsePath(path);
|
||||
for (const { path, data } of files) {
|
||||
console.log(`Patching "${path}"...`);
|
||||
|
||||
const { dir } = parsePath(path);
|
||||
|
||||
try {
|
||||
await mkdir(`${DATA}/${dir}`, { recursive: true });
|
||||
await writeFile(
|
||||
`${DATA}/${path}`,
|
||||
new Uint8Array(writeDVPL(Buffer.from(data))),
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(`Failed to make directory "${dir}"`);
|
||||
}
|
||||
|
||||
bar.tick();
|
||||
}),
|
||||
);
|
||||
const isDvpl = path.endsWith('.dvpl');
|
||||
const buffer = Buffer.from(data);
|
||||
|
||||
await writeFile(
|
||||
`${DATA}/${path}${isDvpl ? '' : '.dvpl'}`,
|
||||
new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)),
|
||||
);
|
||||
|
||||
bar.tick();
|
||||
}
|
||||
|
||||
if ('dynamicContentLocalizationsDir' in data) {
|
||||
console.log('Found dynamic content localizations; patching...');
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DATA_COMPRESSED } from '../../buildAssets/constants';
|
||||
import { readDVPL } from './readDVPL';
|
||||
|
||||
export async function readDVPLFile(file: string) {
|
||||
if (DATA_COMPRESSED) {
|
||||
if (DATA_COMPRESSED && !file.endsWith('.dvpl')) {
|
||||
return readDVPL(await readFile(`${file}.dvpl`));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TextureMutation } from './constants';
|
||||
|
||||
export async function readTexture(path: string, mutation?: TextureMutation) {
|
||||
const ddsTexturePath = path.replace('.tex', '.dx11.dds');
|
||||
const isDds = existsSync(ddsTexturePath);
|
||||
const isDds = existsSync(`${ddsTexturePath}.dvpl`);
|
||||
const resolvedTexturePath = isDds
|
||||
? ddsTexturePath
|
||||
: ddsTexturePath.replace('.dds', '.pvr');
|
||||
|
||||
@@ -30,10 +30,7 @@ export async function commitMultipleFiles(
|
||||
} else if (response.status === 200) {
|
||||
const buffer = Buffer.from(await response.arrayBuffer());
|
||||
|
||||
// we discard blob if they're the same size; it's unlikely their
|
||||
// contents will be different; I love playing russian roulette!
|
||||
const equal = buffer.length === change.content.length || buffer.equals(change.content);
|
||||
if (!equal) {
|
||||
if (!buffer.equals(change.content)) {
|
||||
const diff = change.content.length - buffer.length;
|
||||
|
||||
console.log(
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
SUPPORTED_LOCALES,
|
||||
TranslationTree,
|
||||
} from '@blitzkit/i18n';
|
||||
import { writeFile } from 'fs/promises';
|
||||
|
||||
const ROOT = '@blitzkit/i18n/strings';
|
||||
const WORKING_ROOT = '../../packages/i18n/strings';
|
||||
|
||||
const defaultStrings = require(`${ROOT}/${DEFAULT_LOCALE}.json`).default;
|
||||
const nonDefaultLocales = SUPPORTED_LOCALES.filter(
|
||||
(locale) => locale !== DEFAULT_LOCALE,
|
||||
);
|
||||
|
||||
function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
|
||||
for (const key in strings) {
|
||||
if (key in defaultStrings) {
|
||||
if (typeof defaultStrings[key] === typeof strings[key]) {
|
||||
if (typeof strings[key] === 'string') {
|
||||
if (
|
||||
// are equivalent regardless of %s flavor
|
||||
(defaultStrings[key] as string).replaceAll(/%s\d/g, '%s') ===
|
||||
(strings[key] as string).replaceAll(/%s\d/g, '%s') ||
|
||||
// string is empty
|
||||
strings[key] === '' ||
|
||||
// string has old flavor of %s
|
||||
strings[key].match(/%s([^\d]|$)/g) !== null
|
||||
) {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
prune(defaultStrings[key] as TranslationTree, strings[key]);
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
} else {
|
||||
delete strings[key];
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
for (const locale of nonDefaultLocales) {
|
||||
console.log(`Pruning ${locale}...`);
|
||||
|
||||
const strings = require(`${ROOT}/${locale}.json`).default;
|
||||
const pruned = prune(defaultStrings, strings);
|
||||
|
||||
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
|
||||
}
|
||||
@@ -180,6 +180,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
@@ -191,6 +196,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -275,6 +281,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -285,6 +296,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -357,6 +369,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -367,6 +384,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { asset, TankType, type TankDefinition } from '@blitzkit/core';
|
||||
import {
|
||||
asset,
|
||||
fetchTankDefinitions,
|
||||
TankType,
|
||||
type TankDefinition,
|
||||
} from '@blitzkit/core';
|
||||
import { Flex, Text, type TextProps } from '@radix-ui/themes';
|
||||
import { uniq } from 'lodash-es';
|
||||
import { forwardRef, type ReactNode } from 'react';
|
||||
@@ -16,6 +21,8 @@ type TankCardProps = TextProps & {
|
||||
noLink?: boolean;
|
||||
};
|
||||
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
|
||||
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
|
||||
(
|
||||
{
|
||||
@@ -49,10 +56,9 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
|
||||
onClick={() => {
|
||||
onSelect?.(tank);
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.recentlyViewed = uniq([
|
||||
tank.id,
|
||||
...draft.recentlyViewed,
|
||||
]).slice(0, MAX_RECENTLY_VIEWED);
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}}
|
||||
className="tank-search-card"
|
||||
|
||||
@@ -12,7 +12,7 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
|
||||
return (
|
||||
<Flex flexGrow="1" align="center" justify="center">
|
||||
<Text color="gray">
|
||||
{strings.website.common.tank_search.no_tanks_found.body}.{' '}
|
||||
{strings.website.common.tank_search.no_tanks_found.body}{' '}
|
||||
<Link
|
||||
href="#"
|
||||
underline="always"
|
||||
@@ -25,7 +25,6 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
|
||||
? strings.website.common.tank_search.no_tanks_found.clear_filters
|
||||
: strings.website.common.tank_search.no_tanks_found.search_again}
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,9 @@ export function RecentlyViewed() {
|
||||
const tankopediaPersistentStore = TankopediaPersistent.useStore();
|
||||
const filters = useStore($tankFilters);
|
||||
// non-reactive because it is a little weird that it updates instantly even before the page loads
|
||||
const recentlyViewed = tankopediaPersistentStore.getState().recentlyViewed;
|
||||
const recentlyViewed = tankopediaPersistentStore
|
||||
.getState()
|
||||
.recentlyViewed.filter((id) => id in tankDefinitions.tanks);
|
||||
const sort = useStore($tankopediaSort);
|
||||
const hasFilters = useMemo(
|
||||
() =>
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
metaSortTank,
|
||||
normalizeBoundingBox,
|
||||
resolveDpm,
|
||||
SEARCH_KEYS,
|
||||
unionBoundingBox,
|
||||
type TankDefinition,
|
||||
} from '@blitzkit/core';
|
||||
@@ -410,7 +411,7 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
: sorted.reverse();
|
||||
} else {
|
||||
const searchedRaw = fuzzysort.go(tankFilters.search, tankNames, {
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
keys: SEARCH_KEYS,
|
||||
});
|
||||
const searchedTanks = searchedRaw.map(
|
||||
(result) => tankDefinitions.tanks[result.obj.id],
|
||||
@@ -456,7 +457,9 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
draft.recentlyViewed = uniq([
|
||||
...tanksFiltered.map(({ id }) => id),
|
||||
...draft.recentlyViewed,
|
||||
]).slice(0, MAX_RECENTLY_VIEWED);
|
||||
])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { assertSecret, fetchTankDefinitions } from '@blitzkit/core';
|
||||
import { MinusCircledIcon } from '@radix-ui/react-icons';
|
||||
import { Callout, Flex } from '@radix-ui/themes';
|
||||
import { uniq } from 'lodash-es';
|
||||
@@ -9,6 +9,8 @@ import { AesonPlug } from '../AesonPlug';
|
||||
import { ExperimentIcon } from '../ExperimentIcon';
|
||||
import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants';
|
||||
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
|
||||
export function CalloutsSection() {
|
||||
const tank = Duel.use((state) => state.protagonist.tank);
|
||||
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
|
||||
@@ -17,10 +19,9 @@ export function CalloutsSection() {
|
||||
|
||||
useEffect(() => {
|
||||
mutateTankopediaPersistent((draft) => {
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed]).slice(
|
||||
0,
|
||||
MAX_RECENTLY_VIEWED,
|
||||
);
|
||||
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
|
||||
.filter((id) => id in tankDefinitions.tanks)
|
||||
.slice(0, MAX_RECENTLY_VIEWED);
|
||||
});
|
||||
}, [tank]);
|
||||
|
||||
|
||||
+3
-1
@@ -107,6 +107,7 @@ export function Characteristics() {
|
||||
const hasSupercharger = useEquipment(107);
|
||||
const hasCalibratedShells = useEquipment(103);
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
const penetrationCoefficient = coefficient([
|
||||
hasCalibratedShells,
|
||||
resolvePenetrationCoefficient(true, shell.type) - 1,
|
||||
@@ -129,9 +130,10 @@ export function Characteristics() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
});
|
||||
}, [hasImprovedVerticalStabilizer]);
|
||||
}, [hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
||||
+3
@@ -25,6 +25,7 @@ export function QuickInputs() {
|
||||
const initialGunPitch =
|
||||
tankModelDefinition.initial_turret_rotation?.pitch ?? 0;
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
|
||||
useEffect(() => {
|
||||
if (!yawInput.current) return;
|
||||
@@ -92,6 +93,7 @@ export function QuickInputs() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateDuel((state) => {
|
||||
@@ -133,6 +135,7 @@ export function QuickInputs() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
mutateDuel((state) => {
|
||||
|
||||
+7
@@ -118,6 +118,11 @@ export function Controls({ naked }: ControlsProps) {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
|
||||
switch (event) {
|
||||
case Pose.HullDown: {
|
||||
@@ -127,6 +132,7 @@ export function Controls({ naked }: ControlsProps) {
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
camera.position
|
||||
@@ -159,6 +165,7 @@ export function Controls({ naked }: ControlsProps) {
|
||||
protagonistGunModelDefinition.pitch,
|
||||
protagonistTurretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
camera.position
|
||||
|
||||
+12
@@ -185,6 +185,11 @@ export function TankModel() {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
@@ -196,6 +201,7 @@ export function TankModel() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
@@ -287,6 +293,11 @@ export function TankModel() {
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const hasDownImprovedVerticalStabilizer = await hasEquipment(
|
||||
124,
|
||||
duel.protagonist.tank.equipment_preset,
|
||||
duel.protagonist.equipmentMatrix,
|
||||
);
|
||||
const boundingRect = canvas.getBoundingClientRect();
|
||||
delta.set(event.clientX, event.clientY).sub(position);
|
||||
position.set(event.clientX, event.clientY);
|
||||
@@ -297,6 +308,7 @@ export function TankModel() {
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
}
|
||||
|
||||
+2
@@ -41,6 +41,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||
const protagonistGun = Duel.use((state) => state.protagonist.gun);
|
||||
const protagonistTurret = Duel.use((state) => state.protagonist.turret);
|
||||
const mutateDuel = Duel.useMutation();
|
||||
@@ -82,6 +83,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
gunModelDefinition.pitch,
|
||||
turretModelDefinition.yaw,
|
||||
hasImprovedVerticalStabilizer,
|
||||
hasDownImprovedVerticalStabilizer,
|
||||
);
|
||||
|
||||
modelTransformEvent.emit({ pitch, yaw });
|
||||
|
||||
@@ -12,6 +12,7 @@ export function applyPitchYawLimits(
|
||||
pitchLimits: PitchLimits, // deg
|
||||
yawLimits?: YawLimits, // deg
|
||||
verticalStabilizer = false,
|
||||
downVerticalStabilizer = false,
|
||||
) {
|
||||
let newPitch = pitch;
|
||||
let newYaw = yaw;
|
||||
@@ -22,7 +23,8 @@ export function applyPitchYawLimits(
|
||||
);
|
||||
}
|
||||
|
||||
const depressionBuff = verticalStabilizer ? degToRad(3) : 0;
|
||||
const depressionBuff =
|
||||
verticalStabilizer || downVerticalStabilizer ? degToRad(3) : 0;
|
||||
const elevationBuff = verticalStabilizer ? degToRad(4) : 0;
|
||||
let lowerPitch = -degToRad(pitchLimits.max) - depressionBuff;
|
||||
let upperPitch = -degToRad(pitchLimits.min) + elevationBuff;
|
||||
|
||||
@@ -109,6 +109,7 @@ export function tankCharacteristics(
|
||||
const hasEngineAccelerator = equipment(117);
|
||||
const hasCamouflageNet = equipment(115);
|
||||
const hasImprovedVerticalStabilizer = equipment(122);
|
||||
const hasDownImprovedVerticalStabilizer = equipment(124);
|
||||
const hasImprovedSuspension = equipment(123);
|
||||
|
||||
const hasTungsten = consumable(45);
|
||||
@@ -425,7 +426,8 @@ export function tankCharacteristics(
|
||||
const gunDepression =
|
||||
gunModelDefinition.pitch.max +
|
||||
gunDefaultPitch +
|
||||
(hasImprovedVerticalStabilizer ? 3 : 0);
|
||||
(hasImprovedVerticalStabilizer ? 3 : 0) +
|
||||
(hasDownImprovedVerticalStabilizer ? 3 : 0);
|
||||
const gunElevation =
|
||||
-gunModelDefinition.pitch.min -
|
||||
gunDefaultPitch +
|
||||
|
||||
@@ -29,7 +29,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
<script>
|
||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { getBestLocale } from '../core/i18n/getBestLocale';
|
||||
|
||||
const isAPI = window.location.pathname.startsWith('/api');
|
||||
const isI18nPath = SUPPORTED_LOCALES.some((locale) =>
|
||||
window.location.pathname.startsWith(`/${locale}`),
|
||||
);
|
||||
@@ -38,7 +38,11 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
|
||||
window.location.pathname.startsWith(`/${locale}`),
|
||||
);
|
||||
|
||||
if (bestLocale !== currentPathLocale) {
|
||||
if (
|
||||
!isAPI && // not an api, duh!
|
||||
localStorage.getItem('preferred-locale') !== null && // no preference, so probably google's crawler
|
||||
bestLocale !== currentPathLocale // we need to redirect
|
||||
) {
|
||||
window.location.pathname = isI18nPath
|
||||
? window.location.pathname.replace(
|
||||
`/${currentPathLocale}`,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
||||
import { literals } from '@blitzkit/i18n/src/literals';
|
||||
import { Box, Flex, Heading, Link } from '@radix-ui/themes';
|
||||
import type { GetStaticPaths } from 'astro';
|
||||
import { AesonPlug } from '../../components/AesonPlug';
|
||||
@@ -21,7 +22,6 @@ import {
|
||||
tierListTool,
|
||||
} from '../../constants/tools';
|
||||
import { getStrings } from '../../core/i18n/getStrings';
|
||||
import { literals } from '@blitzkit/i18n/src/literals';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TankSandbox } from '../../../../../components/Tankopedia/HeroSection/co
|
||||
import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
|
||||
import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions';
|
||||
import { LocaleProvider } from '../../../../../hooks/useLocale';
|
||||
import { App } from '../../../../../stores/app';
|
||||
import { Duel } from '../../../../../stores/duel';
|
||||
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
||||
@@ -23,15 +24,17 @@ export function Page({ id }: PageProps) {
|
||||
const model = modelDefinitions.models[id];
|
||||
|
||||
return (
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<Duel.Provider data={{ provisionDefinitions, tank }}>
|
||||
<TankopediaEphemeral.Provider data={model}>
|
||||
<Content />
|
||||
</TankopediaEphemeral.Provider>
|
||||
</Duel.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
<LocaleProvider locale="en">
|
||||
<App.Provider>
|
||||
<TankopediaPersistent.Provider>
|
||||
<Duel.Provider data={{ provisionDefinitions, tank }}>
|
||||
<TankopediaEphemeral.Provider data={model}>
|
||||
<Content />
|
||||
</TankopediaEphemeral.Provider>
|
||||
</Duel.Provider>
|
||||
</TankopediaPersistent.Provider>
|
||||
</App.Provider>
|
||||
</LocaleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+3
-16
@@ -9,28 +9,15 @@ datasource db {
|
||||
}
|
||||
|
||||
model User {
|
||||
blitz_id Int @id @map("blitz") // map: "blitz" was too vague
|
||||
last_used DateTime? @default(now())
|
||||
tank_votes TankVote[]
|
||||
blitz_id BigInt @id @map("blitz") // map: "blitz" was too vague
|
||||
last_used DateTime? @default(now())
|
||||
|
||||
@@map("Users") // map: "Users" was mistakenly plural
|
||||
}
|
||||
|
||||
model TankVote {
|
||||
id Int @id
|
||||
last_updated DateTime @default(now())
|
||||
easiness Int?
|
||||
firepower Int?
|
||||
maneuverability Int?
|
||||
survivability Int?
|
||||
|
||||
user User @relation(fields: [user_blitz_id], references: [blitz_id])
|
||||
user_blitz_id Int
|
||||
}
|
||||
|
||||
model DiscordUser {
|
||||
discord_id BigInt @id @map("discord") // map: "discord" was too vague
|
||||
blitz_id Int @map("blitz") // map: "blitz" was too vague
|
||||
blitz_id BigInt @map("blitz") // map: "blitz" was too vague
|
||||
|
||||
@@map("DiscordUsers") // map: "DiscordUsers" was mistakenly plural
|
||||
}
|
||||
Submodule submodules/blitzkit-closed updated: c1d631764f...31937a9f1e.
Reference in new issue
Block a user