Merge branch 'main' into dev-rinth
No files matched your search
@@ -62,4 +62,6 @@ jobs:
|
|||||||
$env:GH_TOKEN = "${{ secrets.GH_TOKEN }}"
|
$env:GH_TOKEN = "${{ secrets.GH_TOKEN }}"
|
||||||
$env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}"
|
$env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}"
|
||||||
$env:DATABASE_URL = "${{ secrets.DATABASE_URL }}"
|
$env:DATABASE_URL = "${{ secrets.DATABASE_URL }}"
|
||||||
|
$env:VIDEOS_SHEET = "${{ secrets.VIDEOS_SHEET }}"
|
||||||
|
$env:GOOGLE_APPLICATION_CREDENTIALS = "${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}"
|
||||||
yarn build:assets --all-targets --depot ${{ github.ref == 'refs/heads/main' && '--production' || '' }}
|
yarn build:assets --all-targets --depot ${{ github.ref == 'refs/heads/main' && '--production' || '' }}
|
||||||
@@ -18,4 +18,5 @@ temp/
|
|||||||
/.VSCodeCounter
|
/.VSCodeCounter
|
||||||
/.yarn
|
/.yarn
|
||||||
depots
|
depots
|
||||||
public/sitemap*
|
public/sitemap*
|
||||||
|
/firebase.json
|
||||||
@@ -165,6 +165,7 @@
|
|||||||
"xkdkw",
|
"xkdkw",
|
||||||
"XMLDVPL",
|
"XMLDVPL",
|
||||||
"YAMLDVPL",
|
"YAMLDVPL",
|
||||||
|
"youtubers",
|
||||||
"zustand"
|
"zustand"
|
||||||
],
|
],
|
||||||
"deno.enable": false,
|
"deno.enable": false,
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Blitzkrieg 1.19.5
|
||||||
|
|
||||||
|
The tankopedia, now more helpful than ever! This update only affects the website.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- The Tankopedia pages for tanks now include videos from YouTubers
|
||||||
|
- The selection of tanks that have videos is very small currently but you can help expand it by dropping suggestions on [the official Discord server](https://discord.gg/nDt7AjGJQH)
|
||||||
|
- Added shell normalization and ricochet angles to the Tankopedia and Compare
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Removed undefined clipping planes
|
||||||
|
- Added proper keying to all JSX tree nodes, navbar menu items, antagonist bar shells, skill rows and fragments of tank stats in the Tankopedia
|
||||||
|
- The second half of barrels for tanks like the T-100 LT are now properly included
|
||||||
|
|
||||||
|
## Technical Features
|
||||||
|
|
||||||
|
- The list of videos is fetched transpiled from a Google Sheets spreadsheet into a CSV file in the asset repository
|
||||||
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 148 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzrinth",
|
"name": "blitzkrieg",
|
||||||
"version": "1.19.4",
|
"version": "1.19.5",
|
||||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||||
"main": "src/server.ts",
|
"main": "src/server.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"false": "^0.0.4",
|
"false": "^0.0.4",
|
||||||
"fuzzysort": "^2.0.4",
|
"fuzzysort": "^2.0.4",
|
||||||
|
"googleapis": "^134.0.0",
|
||||||
"immer": "^10.0.2",
|
"immer": "^10.0.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
google.com, pub-1289406790225052, DIRECT, f08c47fec0942fa0
|
google.com, pub-1289406790225052, DIRECT, f08c47fec0942fa0
|
||||||
|
appnexus.com, 14163, RESELLER
|
||||||
|
pubcenter.microsoft.com, 253617120, DIRECT
|
||||||
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 921 KiB |
|
Before Width: | Height: | Size: 2.3 MiB After Width: | Height: | Size: 1.9 MiB |
@@ -38,7 +38,7 @@ import { DATA, POI } from './constants';
|
|||||||
import { Avatar } from './skillIcons';
|
import { Avatar } from './skillIcons';
|
||||||
import { TankParameters } from './tankIcons';
|
import { TankParameters } from './tankIcons';
|
||||||
|
|
||||||
interface Strings {
|
export interface BlitzStrings {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
}
|
||||||
type ShellKind =
|
type ShellKind =
|
||||||
@@ -334,7 +334,7 @@ const blitzShellKindToBlitzrinth: Record<ShellKind, ShellType> = {
|
|||||||
const missingStrings: Record<string, string> = {
|
const missingStrings: Record<string, string> = {
|
||||||
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
||||||
};
|
};
|
||||||
const botPattern = /^.+((tutorial_bot(\d+)?)|(TU(R?)))$/;
|
export const botPattern = /^.+((tutorial_bot(\d+)?)|(TU(R?)))$/;
|
||||||
|
|
||||||
export async function definitions(production: boolean) {
|
export async function definitions(production: boolean) {
|
||||||
console.log('Building definitions...');
|
console.log('Building definitions...');
|
||||||
@@ -361,12 +361,12 @@ export async function definitions(production: boolean) {
|
|||||||
(nations) => nations.filter((nation) => nation !== 'common'),
|
(nations) => nations.filter((nation) => nation !== 'common'),
|
||||||
);
|
);
|
||||||
const tankStringIdMap: Record<string, number> = {};
|
const tankStringIdMap: Record<string, number> = {};
|
||||||
const stringsPreInstalled = await readYAMLDVPL<Strings>(
|
const stringsPreInstalled = await readYAMLDVPL<BlitzStrings>(
|
||||||
`${DATA}/${POI.strings}/en.yaml.dvpl`,
|
`${DATA}/${POI.strings}/en.yaml.dvpl`,
|
||||||
);
|
);
|
||||||
const stringsCache = await fetch(POI.cachedStrings)
|
const stringsCache = await fetch(POI.cachedStrings)
|
||||||
.then((response) => response.text())
|
.then((response) => response.text())
|
||||||
.then((string) => parseYaml(string) as Strings);
|
.then((string) => parseYaml(string) as BlitzStrings);
|
||||||
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
|
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
|
||||||
`${DATA}/${POI.optionalDevices}.dvpl`,
|
`${DATA}/${POI.optionalDevices}.dvpl`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,15 +24,17 @@ import { skillIcons } from './skillIcons';
|
|||||||
import { tankArmors } from './tankArmors';
|
import { tankArmors } from './tankArmors';
|
||||||
import { tankIcons } from './tankIcons';
|
import { tankIcons } from './tankIcons';
|
||||||
import { tankModels } from './tankModels';
|
import { tankModels } from './tankModels';
|
||||||
|
import { videos } from './videos';
|
||||||
|
|
||||||
if (!targets && !allTargets) throw new Error('No target(s) specified');
|
if (!targets && !allTargets) throw new Error('No target(s) specified');
|
||||||
|
|
||||||
const methods = [
|
const methods = [
|
||||||
// definitions,
|
definitions,
|
||||||
// scratchedFlags,
|
videos,
|
||||||
// currencies,
|
scratchedFlags,
|
||||||
// skillIcons,
|
currencies,
|
||||||
// circleFlags,
|
skillIcons,
|
||||||
|
circleFlags,
|
||||||
shellIcons,
|
shellIcons,
|
||||||
moduleIcons,
|
moduleIcons,
|
||||||
equipmentIcons,
|
equipmentIcons,
|
||||||
|
|||||||
@@ -28,9 +28,6 @@ export async function tankArmors(production: boolean) {
|
|||||||
if (tankKey.includes('tutorial_bot')) return;
|
if (tankKey.includes('tutorial_bot')) return;
|
||||||
|
|
||||||
const id = toUniqueId(nation, tank.id);
|
const id = toUniqueId(nation, tank.id);
|
||||||
|
|
||||||
console.log(`Building armor ${id} @ ${nation}/${tankKey}`);
|
|
||||||
|
|
||||||
const model = await extractArmor(DATA, `${nation}-${tankKey}`);
|
const model = await extractArmor(DATA, `${nation}-${tankKey}`);
|
||||||
|
|
||||||
changes.push({
|
changes.push({
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ export async function tankModels(production: boolean) {
|
|||||||
if (tankKey.includes('tutorial_bot')) return;
|
if (tankKey.includes('tutorial_bot')) return;
|
||||||
|
|
||||||
const id = toUniqueId(nation, tank.id);
|
const id = toUniqueId(nation, tank.id);
|
||||||
|
|
||||||
console.log(`Building model ${id} @ ${nation}/${tankKey}`);
|
|
||||||
|
|
||||||
const parameters = await readYAMLDVPL<TankParameters>(
|
const parameters = await readYAMLDVPL<TankParameters>(
|
||||||
`${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`,
|
`${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { readdir } from 'fs/promises';
|
||||||
|
import { google } from 'googleapis';
|
||||||
|
import { cloneDeep, uniqBy } from 'lodash';
|
||||||
|
import { parse as parseYaml } from 'yaml';
|
||||||
|
import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL';
|
||||||
|
import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL';
|
||||||
|
import { toUniqueId } from '../../src/core/blitz/toUniqueId';
|
||||||
|
import { commitAssets } from '../../src/core/blitzkrieg/commitAssets';
|
||||||
|
import {
|
||||||
|
VideoDefinitions,
|
||||||
|
videoDefinitions,
|
||||||
|
} from '../../src/core/blitzkrieg/videos';
|
||||||
|
import { DATA, POI } from './constants';
|
||||||
|
import { BlitzStrings, botPattern, VehicleDefinitionList } from './definitions';
|
||||||
|
|
||||||
|
const youtubers = [
|
||||||
|
'UCKBYXp4Xn2I2tL1UL4fpbhw', // droodles
|
||||||
|
'UCrQ-Dy8lVsm11u8pCJ8W7Tw', // fatness
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function videos(production: boolean) {
|
||||||
|
console.log('Building videos...');
|
||||||
|
|
||||||
|
const currentVideos = await videoDefinitions;
|
||||||
|
const auth = await google.auth.getClient({
|
||||||
|
scopes: ['https://www.googleapis.com/auth/youtube.readonly'],
|
||||||
|
});
|
||||||
|
const youtube = google.youtube({ version: 'v3', auth });
|
||||||
|
|
||||||
|
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
|
||||||
|
(nations) => nations.filter((nation) => nation !== 'common'),
|
||||||
|
);
|
||||||
|
const stringsPreInstalled = await readYAMLDVPL<BlitzStrings>(
|
||||||
|
`${DATA}/${POI.strings}/en.yaml.dvpl`,
|
||||||
|
);
|
||||||
|
const stringsCache = await fetch(POI.cachedStrings)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((string) => parseYaml(string) as BlitzStrings);
|
||||||
|
const strings = {
|
||||||
|
...stringsPreInstalled,
|
||||||
|
...stringsCache,
|
||||||
|
};
|
||||||
|
const tanks: { id: number; name: string; tier: number }[] = [];
|
||||||
|
await Promise.all(
|
||||||
|
nations.map(async (nation) => {
|
||||||
|
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
|
||||||
|
`${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(tankList.root).map(async ([tankKey, tank]) => {
|
||||||
|
if (botPattern.test(tankKey)) return null;
|
||||||
|
|
||||||
|
const id = toUniqueId(nation, tank.id);
|
||||||
|
const name =
|
||||||
|
(tank.shortUserString
|
||||||
|
? strings[tank.shortUserString]
|
||||||
|
: undefined) ?? strings[tank.userString];
|
||||||
|
const tier = tank.level;
|
||||||
|
|
||||||
|
tanks.push({ id, name, tier });
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const tanksSanitized = tanks
|
||||||
|
.sort((a, b) => b.tier - a.tier)
|
||||||
|
.sort((a, b) => {
|
||||||
|
const lastUpdatedA = currentVideos[a.id]?.lastUpdated ?? 0;
|
||||||
|
const lastUpdatedB = currentVideos[b.id]?.lastUpdated ?? 0;
|
||||||
|
return lastUpdatedA - lastUpdatedB;
|
||||||
|
});
|
||||||
|
const videos: VideoDefinitions = cloneDeep(currentVideos);
|
||||||
|
|
||||||
|
let done = 0;
|
||||||
|
for (const tank of tanksSanitized) {
|
||||||
|
try {
|
||||||
|
const results = await youtube.search.list({
|
||||||
|
part: ['snippet'],
|
||||||
|
q: `World of Tanks Blitz ${tank.name}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!results.data.items || results.data.items.length === 0) continue;
|
||||||
|
|
||||||
|
const items = uniqBy(
|
||||||
|
results.data.items.filter(
|
||||||
|
(item) =>
|
||||||
|
item.snippet?.channelId &&
|
||||||
|
item.id?.videoId &&
|
||||||
|
youtubers.includes(item.snippet.channelId),
|
||||||
|
),
|
||||||
|
(item) => item.snippet!.channelId,
|
||||||
|
);
|
||||||
|
|
||||||
|
videos[tank.id] = {
|
||||||
|
lastUpdated: Math.round(Date.now() / 1000),
|
||||||
|
videos: items.map((item) => item.id!.videoId!),
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${++done} / ${tanks.length} (${Math.round(100 * (done / tanks.length))}%) done; found ${items.length} for ${tank.name}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000 / 5));
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('An error occurred, safely exiting prematurely...', error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = Object.entries(videos)
|
||||||
|
.map(
|
||||||
|
([id, { videos, lastUpdated }]) =>
|
||||||
|
`${id},${lastUpdated},${videos.join(',')}`,
|
||||||
|
)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
await commitAssets(
|
||||||
|
'videos',
|
||||||
|
[{ content, encoding: 'utf-8', path: 'definitions/videos.csv' }],
|
||||||
|
production,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,9 +7,9 @@ import { Roboto_Flex } from 'next/font/google';
|
|||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { ReactNode, Suspense, useEffect, useState } from 'react';
|
import { ReactNode, Suspense, useEffect, useState } from 'react';
|
||||||
import { Footer } from '../components/Footer';
|
import { Footer } from '../components/Footer';
|
||||||
import { Google } from '../components/Google';
|
|
||||||
import { Loader } from '../components/Loader';
|
import { Loader } from '../components/Loader';
|
||||||
import Navbar from '../components/Navbar';
|
import Navbar from '../components/Navbar';
|
||||||
|
import { Party3 } from '../components/Party3';
|
||||||
import isDev from '../core/blitzrinth/isDev';
|
import isDev from '../core/blitzrinth/isDev';
|
||||||
import { isLocalhost } from '../core/blitzrinth/isLocalhost';
|
import { isLocalhost } from '../core/blitzrinth/isLocalhost';
|
||||||
import { useFullScreen } from '../hooks/useFullScreen';
|
import { useFullScreen } from '../hooks/useFullScreen';
|
||||||
@@ -60,7 +60,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
|||||||
<meta property="og:site_name" content="Blitzrinth" />
|
<meta property="og:site_name" content="Blitzrinth" />
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
|
|
||||||
<Google />
|
<Party3 />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
|
|||||||
@@ -1233,10 +1233,21 @@ export default function Page() {
|
|||||||
<Row name="Shells" value="shells" decimals={0} />
|
<Row name="Shells" value="shells" decimals={0} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Row name="Caliber" value="caliber" decimals={0} />
|
|
||||||
<Row name="Penetration" value="penetration" decimals={0} />
|
<Row name="Penetration" value="penetration" decimals={0} />
|
||||||
<Row name="Damage" value="damage" decimals={0} />
|
<Row name="Damage" value="damage" decimals={0} />
|
||||||
<Row name="Module damage" value="moduleDamage" decimals={0} />
|
<Row name="Module damage" value="moduleDamage" decimals={0} />
|
||||||
|
<Row name="Caliber" value="caliber" decimals={0} />
|
||||||
|
<Row
|
||||||
|
name="Normalization"
|
||||||
|
value="shellNormalization"
|
||||||
|
decimals={0}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
name="Ricochet"
|
||||||
|
value="shellRicochet"
|
||||||
|
deltaType="lowerIsBetter"
|
||||||
|
decimals={0}
|
||||||
|
/>
|
||||||
<Row name="Shell velocity" value="shellVelocity" decimals={0} />
|
<Row name="Shell velocity" value="shellVelocity" decimals={0} />
|
||||||
<Row
|
<Row
|
||||||
name="Aim time"
|
name="Aim time"
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ export function AntagonistBar({ floating }: AntagonistBarProps) {
|
|||||||
<Flex>
|
<Flex>
|
||||||
{antagonist.turret.guns.map((gun, index) => (
|
{antagonist.turret.guns.map((gun, index) => (
|
||||||
<ModuleButton
|
<ModuleButton
|
||||||
|
key={gun.id}
|
||||||
rowChild
|
rowChild
|
||||||
first={index === 0}
|
first={index === 0}
|
||||||
last={
|
last={
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
TextField,
|
TextField,
|
||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { use, useEffect, useRef, useState } from 'react';
|
import { Fragment, use, useEffect, useRef, useState } from 'react';
|
||||||
import { lerp } from 'three/src/math/MathUtils';
|
import { lerp } from 'three/src/math/MathUtils';
|
||||||
import { ShellButton } from '../../../../../../components/ModuleButtons/ShellButton';
|
import { ShellButton } from '../../../../../../components/ModuleButtons/ShellButton';
|
||||||
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits';
|
||||||
@@ -155,7 +155,6 @@ export function Characteristics() {
|
|||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info>
|
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info>
|
||||||
<InfoWithDelta name="DPM" decimals={0} unit="hp / min">
|
<InfoWithDelta name="DPM" decimals={0} unit="hp / min">
|
||||||
{stats.dpm}
|
{stats.dpm}
|
||||||
@@ -189,7 +188,6 @@ export function Characteristics() {
|
|||||||
{gun.type !== 'regular' && (
|
{gun.type !== 'regular' && (
|
||||||
<InfoWithDelta name="Shells">{stats.shells}</InfoWithDelta>
|
<InfoWithDelta name="Shells">{stats.shells}</InfoWithDelta>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{gun.type === 'autoReloader' ? (
|
{gun.type === 'autoReloader' ? (
|
||||||
<>
|
<>
|
||||||
<Info indent name="Most optimal">
|
<Info indent name="Most optimal">
|
||||||
@@ -229,9 +227,6 @@ export function Characteristics() {
|
|||||||
{stats.intraClip!}
|
{stats.intraClip!}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
)}
|
)}
|
||||||
<InfoWithDelta name="Caliber" decimals={0} unit="mm">
|
|
||||||
{stats.caliber}
|
|
||||||
</InfoWithDelta>
|
|
||||||
<InfoWithDelta decimals={0} name="Penetration" unit="mm">
|
<InfoWithDelta decimals={0} name="Penetration" unit="mm">
|
||||||
{stats.penetration}
|
{stats.penetration}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
@@ -295,6 +290,22 @@ export function Characteristics() {
|
|||||||
{stats.explosionRadius!}
|
{stats.explosionRadius!}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
)}
|
)}
|
||||||
|
<InfoWithDelta name="Caliber" decimals={0} unit="mm">
|
||||||
|
{stats.caliber}
|
||||||
|
</InfoWithDelta>
|
||||||
|
<InfoWithDelta name="Normalization" decimals={0} unit="°">
|
||||||
|
{stats.shellNormalization}
|
||||||
|
</InfoWithDelta>
|
||||||
|
{shell.type !== 'he' && (
|
||||||
|
<InfoWithDelta
|
||||||
|
name="Ricochet"
|
||||||
|
decimals={0}
|
||||||
|
deltaType="lowerIsBetter"
|
||||||
|
unit="°"
|
||||||
|
>
|
||||||
|
{stats.shellRicochet!}
|
||||||
|
</InfoWithDelta>
|
||||||
|
)}
|
||||||
<InfoWithDelta name="Shell velocity" unit="m/s" decimals={0}>
|
<InfoWithDelta name="Shell velocity" unit="m/s" decimals={0}>
|
||||||
{stats.shellVelocity}
|
{stats.shellVelocity}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
@@ -516,7 +527,7 @@ export function Characteristics() {
|
|||||||
const count = member.count ?? 1;
|
const count = member.count ?? 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Fragment key={member.type}>
|
||||||
<InfoWithDelta
|
<InfoWithDelta
|
||||||
key={`${member.type}-root`}
|
key={`${member.type}-root`}
|
||||||
name={`${CREW_MEMBER_NAMES[member.type]}${count > 1 ? ` x ${count}` : ''}`}
|
name={`${CREW_MEMBER_NAMES[member.type]}${count > 1 ? ` x ${count}` : ''}`}
|
||||||
@@ -545,7 +556,7 @@ export function Characteristics() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -124,11 +124,15 @@ export const TankModel = memo(() => {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<group ref={turretContainer}>
|
<group ref={turretContainer}>
|
||||||
@@ -189,11 +193,15 @@ export const TankModel = memo(() => {
|
|||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<group ref={gunContainer}>
|
<group ref={gunContainer}>
|
||||||
@@ -255,11 +263,15 @@ export const TankModel = memo(() => {
|
|||||||
window.removeEventListener('pointerup', handlePointerUp);
|
window.removeEventListener('pointerup', handlePointerUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsxTree(node, {
|
return jsxTree(
|
||||||
castShadow: true,
|
node,
|
||||||
receiveShadow: true,
|
{
|
||||||
onPointerDown,
|
castShadow: true,
|
||||||
});
|
receiveShadow: true,
|
||||||
|
onPointerDown,
|
||||||
|
},
|
||||||
|
node.uuid,
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { InfoCircledIcon, PlusIcon } from '@radix-ui/react-icons';
|
||||||
|
import { Callout, Card, Flex, Heading, Link, Text } from '@radix-ui/themes';
|
||||||
|
import { use } from 'react';
|
||||||
|
import { videoDefinitions } from '../../../../../core/blitzkrieg/videos';
|
||||||
|
import { useFullScreen } from '../../../../../hooks/useFullScreen';
|
||||||
|
import { useDuel } from '../../../../../stores/duel';
|
||||||
|
|
||||||
|
export function Videos() {
|
||||||
|
const isFullScreen = useFullScreen();
|
||||||
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
|
const awaitedVideoDefinitions = use(videoDefinitions);
|
||||||
|
const videos = awaitedVideoDefinitions[tank.id]?.videos ?? [];
|
||||||
|
|
||||||
|
if (isFullScreen) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" gap="4" mt="4" align="start">
|
||||||
|
<Heading size="6">Review videos</Heading>
|
||||||
|
|
||||||
|
<Callout.Root>
|
||||||
|
<Callout.Icon>
|
||||||
|
<InfoCircledIcon />
|
||||||
|
</Callout.Icon>
|
||||||
|
<Callout.Text>
|
||||||
|
Some YouTubers may not have videos on the {tank.name} leading to
|
||||||
|
off-topic videos.
|
||||||
|
</Callout.Text>
|
||||||
|
</Callout.Root>
|
||||||
|
|
||||||
|
<Flex gap="3" wrap="wrap">
|
||||||
|
{videos.map((video) => (
|
||||||
|
<Link
|
||||||
|
key={video}
|
||||||
|
href={`https://www.youtube.com/watch?v=${video}`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={`https://i.ytimg.com/vi/${video}/hqdefault.jpg`}
|
||||||
|
style={{
|
||||||
|
aspectRatio: '16 / 9',
|
||||||
|
objectFit: 'cover',
|
||||||
|
height: 128,
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Link href="https://discord.gg/nDt7AjGJQH" target="_blank">
|
||||||
|
<Card
|
||||||
|
style={{
|
||||||
|
aspectRatio: '16 / 9',
|
||||||
|
height: 128,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
gap="1"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text color="purple">
|
||||||
|
{videos.length === 0 ? 'Suggest' : 'Suggest more'} <PlusIcon />
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
</Link>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import { Provisions } from './components/Characteristics/components/Provisions';
|
|||||||
import { Skills } from './components/Characteristics/components/Skills';
|
import { Skills } from './components/Characteristics/components/Skills';
|
||||||
import { TankSandbox } from './components/Model/TankSandbox';
|
import { TankSandbox } from './components/Model/TankSandbox';
|
||||||
import { Title } from './components/Title';
|
import { Title } from './components/Title';
|
||||||
|
import { Videos } from './components/Videos';
|
||||||
|
|
||||||
export default function Page({ params }: { params: { id: string } }) {
|
export default function Page({ params }: { params: { id: string } }) {
|
||||||
const initialId = parseInt(params.id);
|
const initialId = parseInt(params.id);
|
||||||
@@ -83,7 +84,7 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
top: 64,
|
top: 64 + 16,
|
||||||
position: wideFormat ? 'sticky' : undefined,
|
position: wideFormat ? 'sticky' : undefined,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -91,7 +92,6 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
<TankSandbox />
|
<TankSandbox />
|
||||||
<AntagonistBar />
|
<AntagonistBar />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex gap="5" wrap="wrap">
|
<Flex gap="5" wrap="wrap">
|
||||||
<Modules />
|
<Modules />
|
||||||
<Provisions />
|
<Provisions />
|
||||||
@@ -110,6 +110,8 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
<Characteristics />
|
<Characteristics />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
<Videos />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import { Flex, Link } from '@radix-ui/themes';
|
import { Flex, Link } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
import { use } from 'react';
|
||||||
|
import { AdHorizontal } from '../../../../components/Ads/Horizontal';
|
||||||
import PageWrapper from '../../../../components/PageWrapper';
|
import PageWrapper from '../../../../components/PageWrapper';
|
||||||
import { tankDefinitions } from '../../../../core/blitzrinth/tankDefinitions';
|
import { tankDefinitions } from '../../../../core/blitzrinth/tankDefinitions';
|
||||||
|
|
||||||
@@ -8,11 +11,17 @@ export default function Page() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper>
|
<PageWrapper>
|
||||||
|
<title>Super duper secret map for SEO</title>
|
||||||
|
|
||||||
|
<AdHorizontal />
|
||||||
|
|
||||||
<Flex direction="column" align="center">
|
<Flex direction="column" align="center">
|
||||||
{Object.values(awaitedTankDefinitions)
|
{Object.values(awaitedTankDefinitions)
|
||||||
.sort((a, b) => b.tier - a.tier)
|
.sort((a, b) => b.tier - a.tier)
|
||||||
.map((tank) => (
|
.map((tank) => (
|
||||||
<Link href={`./${tank.id}`}>{tank.name}</Link>
|
<Link href={`./${tank.id}`} key={tank.id}>
|
||||||
|
{tank.name}
|
||||||
|
</Link>
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export function AdHorizontal() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1289406790225052"
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
/>
|
||||||
|
<ins
|
||||||
|
className="adsbygoogle"
|
||||||
|
style={{ display: 'block' }}
|
||||||
|
data-ad-client="ca-pub-1289406790225052"
|
||||||
|
data-ad-slot="2391822409"
|
||||||
|
data-ad-format="auto"
|
||||||
|
data-full-width-responsive="true"
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `(adsbygoogle = window.adsbygoogle || []).push({});`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -153,14 +153,12 @@ export function CoreArmorSceneComponent({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 0,
|
node,
|
||||||
material: excludeMaterial,
|
{ renderOrder: 0, material: excludeMaterial },
|
||||||
})}
|
`${node.uuid}-exclude`,
|
||||||
{jsxTree(node, {
|
)}
|
||||||
renderOrder: 1,
|
{jsxTree(node, { renderOrder: 1, material }, `${node.uuid}-include`)}
|
||||||
material,
|
|
||||||
})}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -259,9 +259,9 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(({ scene }) => {
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
{modelNodes.map((node) => {
|
{modelNodes.map((node) => {
|
||||||
const isCurrentGun =
|
const isCurrentGun = node.name.startsWith(
|
||||||
node.name ===
|
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
|
||||||
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`;
|
);
|
||||||
const isVisible = isCurrentGun;
|
const isVisible = isCurrentGun;
|
||||||
|
|
||||||
if (!isVisible) return null;
|
if (!isVisible) return null;
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ export function SpacedArmorSubExternal({
|
|||||||
depthTest: true,
|
depthTest: true,
|
||||||
depthWrite: false,
|
depthWrite: false,
|
||||||
blending: AdditiveBlending,
|
blending: AdditiveBlending,
|
||||||
clippingPlanes: clip ? [clip] : undefined,
|
clipping: clip !== undefined,
|
||||||
clipping: true,
|
...(clip ? { clippingPlanes: [clip] } : {}),
|
||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
thickness: { value: null },
|
thickness: { value: null },
|
||||||
@@ -107,26 +107,27 @@ export function SpacedArmorSubExternal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 3,
|
node,
|
||||||
material: new MeshBasicMaterial({
|
{
|
||||||
colorWrite: false,
|
renderOrder: 3,
|
||||||
depthTest: true,
|
material: new MeshBasicMaterial({
|
||||||
depthWrite: true,
|
colorWrite: false,
|
||||||
clippingPlanes: clip ? [clip] : undefined,
|
depthTest: true,
|
||||||
}),
|
depthWrite: true,
|
||||||
onClick() {},
|
...(clip ? { clippingPlanes: [clip] } : {}),
|
||||||
userData: {
|
}),
|
||||||
type: ArmorType.External,
|
onClick() {},
|
||||||
thickness,
|
userData: {
|
||||||
variant,
|
type: ArmorType.External,
|
||||||
} satisfies ArmorUserData,
|
thickness,
|
||||||
})}
|
variant,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
},
|
||||||
|
`${node.uuid}-exclude`,
|
||||||
|
)}
|
||||||
|
|
||||||
{jsxTree(node, {
|
{jsxTree(node, { renderOrder: 4, material }, `${node.uuid}-include`)}
|
||||||
renderOrder: 4,
|
|
||||||
material,
|
|
||||||
})}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -113,20 +113,28 @@ export function SpacedArmorSubSpaced({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 2,
|
node,
|
||||||
material,
|
{
|
||||||
onClick() {},
|
renderOrder: 2,
|
||||||
userData: {
|
material,
|
||||||
type: ArmorType.Spaced,
|
onClick() {},
|
||||||
thickness,
|
userData: {
|
||||||
} satisfies ArmorUserData,
|
type: ArmorType.Spaced,
|
||||||
})}
|
thickness,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
},
|
||||||
|
`${node.uuid}-exclude`,
|
||||||
|
)}
|
||||||
|
|
||||||
{jsxTree(node, {
|
{jsxTree(
|
||||||
renderOrder: 5,
|
node,
|
||||||
material: depthWriteMaterial,
|
{
|
||||||
})}
|
renderOrder: 5,
|
||||||
|
material: depthWriteMaterial,
|
||||||
|
},
|
||||||
|
`${node.uuid}-include`,
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -81,251 +81,265 @@ export function SpacedArmorSceneComponent({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{props.type === ArmorType.Core &&
|
{props.type === ArmorType.Core &&
|
||||||
jsxTree(node, {
|
jsxTree(
|
||||||
renderOrder: 0,
|
node,
|
||||||
material: omitMaterial,
|
{
|
||||||
userData: {
|
renderOrder: 0,
|
||||||
type: ArmorType.Core,
|
material: omitMaterial,
|
||||||
thickness,
|
userData: {
|
||||||
} satisfies ArmorUserData,
|
type: ArmorType.Core,
|
||||||
|
thickness,
|
||||||
|
} satisfies ArmorUserData,
|
||||||
|
|
||||||
async onClick(event) {
|
async onClick(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
const duel = useDuel.getState();
|
const duel = useDuel.getState();
|
||||||
const hasCalibratedShells = await hasEquipment(
|
const hasCalibratedShells = await hasEquipment(
|
||||||
103,
|
103,
|
||||||
duel.antagonist!.tank.equipment,
|
duel.antagonist!.tank.equipment,
|
||||||
duel.antagonist!.equipmentMatrix,
|
duel.antagonist!.equipmentMatrix,
|
||||||
);
|
|
||||||
const hasEnhancedArmor = await hasEquipment(
|
|
||||||
110,
|
|
||||||
duel.protagonist!.tank.equipment,
|
|
||||||
duel.protagonist!.equipmentMatrix,
|
|
||||||
);
|
|
||||||
const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1;
|
|
||||||
const shell = useDuel.getState().antagonist!.shell;
|
|
||||||
const explosive = isExplosive(shell.type);
|
|
||||||
const splashing = canSplash(shell.type);
|
|
||||||
const penetration =
|
|
||||||
resolveNearPenetration(shell.penetration) *
|
|
||||||
(hasCalibratedShells
|
|
||||||
? isExplosive(shell.type)
|
|
||||||
? 1.1
|
|
||||||
: 1.05
|
|
||||||
: 1);
|
|
||||||
const shot: Shot = {
|
|
||||||
layers: [],
|
|
||||||
point: event.point,
|
|
||||||
}; // TODO: type this
|
|
||||||
let remainingPenetration = penetration;
|
|
||||||
|
|
||||||
const shellNormal = camera.position
|
|
||||||
.clone()
|
|
||||||
.sub(event.point)
|
|
||||||
.normalize();
|
|
||||||
|
|
||||||
pushLogs(shellNormal, filterIntersections(event.intersections), 0);
|
|
||||||
|
|
||||||
function filterIntersections(intersectionsRaw: Intersection[]) {
|
|
||||||
const showSpacedArmor =
|
|
||||||
useTankopediaPersistent.getState().model.visual.showSpacedArmor;
|
|
||||||
const intersectionsTyped = intersectionsRaw.filter(
|
|
||||||
({ object }) => object.userData.type !== undefined,
|
|
||||||
) as ArmorMeshIntersection[];
|
|
||||||
const intersectionsFiltered = intersectionsTyped.filter(
|
|
||||||
({ object }) =>
|
|
||||||
showSpacedArmor
|
|
||||||
? true
|
|
||||||
: object.userData.type === ArmorType.Core,
|
|
||||||
);
|
);
|
||||||
const intersectionsWithDuplicates = intersectionsFiltered.slice(
|
const hasEnhancedArmor = await hasEquipment(
|
||||||
|
110,
|
||||||
|
duel.protagonist!.tank.equipment,
|
||||||
|
duel.protagonist!.equipmentMatrix,
|
||||||
|
);
|
||||||
|
const thicknessCoefficient = hasEnhancedArmor ? 1.04 : 1;
|
||||||
|
const shell = useDuel.getState().antagonist!.shell;
|
||||||
|
const explosive = isExplosive(shell.type);
|
||||||
|
const splashing = canSplash(shell.type);
|
||||||
|
const penetration =
|
||||||
|
resolveNearPenetration(shell.penetration) *
|
||||||
|
(hasCalibratedShells
|
||||||
|
? isExplosive(shell.type)
|
||||||
|
? 1.1
|
||||||
|
: 1.05
|
||||||
|
: 1);
|
||||||
|
const shot: Shot = {
|
||||||
|
layers: [],
|
||||||
|
point: event.point,
|
||||||
|
}; // TODO: type this
|
||||||
|
let remainingPenetration = penetration;
|
||||||
|
|
||||||
|
const shellNormal = camera.position
|
||||||
|
.clone()
|
||||||
|
.sub(event.point)
|
||||||
|
.normalize();
|
||||||
|
|
||||||
|
pushLogs(
|
||||||
|
shellNormal,
|
||||||
|
filterIntersections(event.intersections),
|
||||||
0,
|
0,
|
||||||
intersectionsFiltered.findIndex(
|
|
||||||
({ object }) => object.userData.type === ArmorType.Core,
|
|
||||||
) + 1,
|
|
||||||
);
|
);
|
||||||
const firstGunIntersectionIndex =
|
|
||||||
intersectionsWithDuplicates.findIndex(
|
function filterIntersections(intersectionsRaw: Intersection[]) {
|
||||||
|
const showSpacedArmor =
|
||||||
|
useTankopediaPersistent.getState().model.visual
|
||||||
|
.showSpacedArmor;
|
||||||
|
const intersectionsTyped = intersectionsRaw.filter(
|
||||||
|
({ object }) => object.userData.type !== undefined,
|
||||||
|
) as ArmorMeshIntersection[];
|
||||||
|
const intersectionsFiltered = intersectionsTyped.filter(
|
||||||
({ object }) =>
|
({ object }) =>
|
||||||
object.userData.type === ArmorType.External &&
|
showSpacedArmor
|
||||||
object.userData.variant === 'gun',
|
? true
|
||||||
|
: object.userData.type === ArmorType.Core,
|
||||||
);
|
);
|
||||||
const firstTrackIntersectionIndex =
|
const intersectionsWithDuplicates = intersectionsFiltered.slice(
|
||||||
intersectionsWithDuplicates.findIndex(
|
0,
|
||||||
({ object }) =>
|
intersectionsFiltered.findIndex(
|
||||||
object.userData.type === ArmorType.External &&
|
({ object }) => object.userData.type === ArmorType.Core,
|
||||||
object.userData.variant === 'track',
|
) + 1,
|
||||||
);
|
);
|
||||||
let intersections = intersectionsWithDuplicates;
|
const firstGunIntersectionIndex =
|
||||||
|
intersectionsWithDuplicates.findIndex(
|
||||||
if (firstGunIntersectionIndex !== -1) {
|
({ object }) =>
|
||||||
intersections = intersections.filter(({ object }, index) => {
|
object.userData.type === ArmorType.External &&
|
||||||
return object.userData.type === ArmorType.External &&
|
object.userData.variant === 'gun',
|
||||||
object.userData.variant === 'gun'
|
|
||||||
? index === firstGunIntersectionIndex
|
|
||||||
: true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (firstTrackIntersectionIndex !== -1) {
|
|
||||||
intersections = intersections.filter(({ object }, index) => {
|
|
||||||
return object.userData.type === ArmorType.External &&
|
|
||||||
object.userData.variant === 'track'
|
|
||||||
? index === firstTrackIntersectionIndex
|
|
||||||
: true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return intersections;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pushLogs(
|
|
||||||
shellNormal: Vector3,
|
|
||||||
intersections: ArmorMeshIntersection[],
|
|
||||||
startingIndex: number,
|
|
||||||
) {
|
|
||||||
let layerIndex = startingIndex;
|
|
||||||
let loopIndex = 0;
|
|
||||||
|
|
||||||
if (layerIndex !== 0 && intersections.length > 0) {
|
|
||||||
const distance = (
|
|
||||||
shot.layers.at(-1) as ShotLayerBase
|
|
||||||
).point.distanceTo(intersections[0].point);
|
|
||||||
if (explosive && !splashing)
|
|
||||||
remainingPenetration -= 0.5 * remainingPenetration * distance;
|
|
||||||
const blocked = remainingPenetration < 0;
|
|
||||||
|
|
||||||
shot.layers.push({
|
|
||||||
type: null,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
|
||||||
distance,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (blocked) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const intersection of intersections) {
|
|
||||||
const surfaceNormal = intersection
|
|
||||||
.normal!.clone()
|
|
||||||
.applyQuaternion(
|
|
||||||
event.object.getWorldQuaternion(new Quaternion()),
|
|
||||||
);
|
);
|
||||||
const thickness =
|
const firstTrackIntersectionIndex =
|
||||||
thicknessCoefficient * intersection.object.userData.thickness;
|
intersectionsWithDuplicates.findIndex(
|
||||||
|
({ object }) =>
|
||||||
|
object.userData.type === ArmorType.External &&
|
||||||
|
object.userData.variant === 'track',
|
||||||
|
);
|
||||||
|
let intersections = intersectionsWithDuplicates;
|
||||||
|
|
||||||
if (layerIndex !== 0 && startingIndex === 0) {
|
if (firstGunIntersectionIndex !== -1) {
|
||||||
const previousIntersection = intersections[layerIndex - 1];
|
intersections = intersections.filter(({ object }, index) => {
|
||||||
const distance =
|
return object.userData.type === ArmorType.External &&
|
||||||
intersection.distance - previousIntersection.distance;
|
object.userData.variant === 'gun'
|
||||||
|
? index === firstGunIntersectionIndex
|
||||||
|
: true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (firstTrackIntersectionIndex !== -1) {
|
||||||
|
intersections = intersections.filter(({ object }, index) => {
|
||||||
|
return object.userData.type === ArmorType.External &&
|
||||||
|
object.userData.variant === 'track'
|
||||||
|
? index === firstTrackIntersectionIndex
|
||||||
|
: true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pushLogs(
|
||||||
|
shellNormal: Vector3,
|
||||||
|
intersections: ArmorMeshIntersection[],
|
||||||
|
startingIndex: number,
|
||||||
|
) {
|
||||||
|
let layerIndex = startingIndex;
|
||||||
|
let loopIndex = 0;
|
||||||
|
|
||||||
|
if (layerIndex !== 0 && intersections.length > 0) {
|
||||||
|
const distance = (
|
||||||
|
shot.layers.at(-1) as ShotLayerBase
|
||||||
|
).point.distanceTo(intersections[0].point);
|
||||||
if (explosive && !splashing)
|
if (explosive && !splashing)
|
||||||
remainingPenetration -=
|
remainingPenetration -=
|
||||||
0.5 * remainingPenetration * distance;
|
0.5 * remainingPenetration * distance;
|
||||||
const wasted = remainingPenetration < 0;
|
|
||||||
|
|
||||||
shot.layers.push({
|
|
||||||
type: null,
|
|
||||||
status: wasted ? 'blocked' : 'penetration',
|
|
||||||
distance,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (wasted && !splashing) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intersection.object.userData.type === ArmorType.External) {
|
|
||||||
remainingPenetration -= thickness;
|
|
||||||
const blocked = remainingPenetration < 0;
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type: ArmorType.External,
|
type: null,
|
||||||
index: layerIndex,
|
|
||||||
shellNormal,
|
|
||||||
surfaceNormal,
|
|
||||||
point: intersection.point,
|
|
||||||
thickness: intersection.object.userData.thickness,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
|
distance,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (splashing) {
|
if (blocked) return;
|
||||||
remainingPenetration = Math.max(0, remainingPenetration);
|
}
|
||||||
} else if (blocked) {
|
|
||||||
break;
|
for (const intersection of intersections) {
|
||||||
}
|
const surfaceNormal = intersection
|
||||||
} else {
|
.normal!.clone()
|
||||||
const type = intersection.object.userData.type;
|
.applyQuaternion(
|
||||||
const angle = surfaceNormal.angleTo(shellNormal);
|
event.object.getWorldQuaternion(new Quaternion()),
|
||||||
const ricochet = degToRad(shell.ricochet ?? 90);
|
);
|
||||||
const normalization = degToRad(shell.normalization ?? 0);
|
const thickness =
|
||||||
const threeCalibersRule =
|
thicknessCoefficient *
|
||||||
shell.caliber > thickness * 3 || layerIndex > 0;
|
intersection.object.userData.thickness;
|
||||||
const twoCalibersRule = shell.caliber > thickness * 2;
|
|
||||||
const finalNormalization = twoCalibersRule
|
if (layerIndex !== 0 && startingIndex === 0) {
|
||||||
? (1.4 * normalization * shell.caliber) / (2.0 * thickness)
|
const previousIntersection = intersections[layerIndex - 1];
|
||||||
: normalization;
|
const distance =
|
||||||
const finalThickness =
|
intersection.distance - previousIntersection.distance;
|
||||||
thickness === 0
|
if (explosive && !splashing)
|
||||||
? 0
|
remainingPenetration -=
|
||||||
: thickness /
|
0.5 * remainingPenetration * distance;
|
||||||
Math.cos(Math.max(0, angle - finalNormalization));
|
const wasted = remainingPenetration < 0;
|
||||||
|
|
||||||
if (!threeCalibersRule && angle >= ricochet) {
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type,
|
type: null,
|
||||||
index: layerIndex,
|
status: wasted ? 'blocked' : 'penetration',
|
||||||
shellNormal,
|
distance,
|
||||||
surfaceNormal,
|
|
||||||
point: intersection.point,
|
|
||||||
thickness,
|
|
||||||
thicknessAngled: finalThickness,
|
|
||||||
angle,
|
|
||||||
status: 'ricochet',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
remainingPenetration *= 0.75;
|
if (wasted && !splashing) return;
|
||||||
|
}
|
||||||
|
|
||||||
const raycaster = new Raycaster();
|
if (
|
||||||
const newShellNormal = shellNormal
|
intersection.object.userData.type === ArmorType.External
|
||||||
.clone()
|
) {
|
||||||
.reflect(surfaceNormal);
|
remainingPenetration -= thickness;
|
||||||
const newCameraNormal = newShellNormal
|
|
||||||
.clone()
|
|
||||||
.multiplyScalar(-1);
|
|
||||||
|
|
||||||
raycaster.set(intersection.point, newCameraNormal);
|
|
||||||
pushLogs(
|
|
||||||
newShellNormal,
|
|
||||||
filterIntersections(
|
|
||||||
raycaster.intersectObjects(scene.children, true),
|
|
||||||
),
|
|
||||||
layerIndex + 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
remainingPenetration -= finalThickness;
|
|
||||||
const blocked = remainingPenetration < 0;
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
shot.layers.push({
|
shot.layers.push({
|
||||||
type,
|
type: ArmorType.External,
|
||||||
index: layerIndex,
|
index: layerIndex,
|
||||||
shellNormal,
|
shellNormal,
|
||||||
surfaceNormal,
|
surfaceNormal,
|
||||||
point: intersection.point,
|
point: intersection.point,
|
||||||
thickness,
|
thickness: intersection.object.userData.thickness,
|
||||||
thicknessAngled: finalThickness,
|
|
||||||
angle,
|
|
||||||
status: blocked ? 'blocked' : 'penetration',
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (splashing) {
|
||||||
|
remainingPenetration = Math.max(0, remainingPenetration);
|
||||||
|
} else if (blocked) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const type = intersection.object.userData.type;
|
||||||
|
const angle = surfaceNormal.angleTo(shellNormal);
|
||||||
|
const ricochet = degToRad(shell.ricochet ?? 90);
|
||||||
|
const normalization = degToRad(shell.normalization ?? 0);
|
||||||
|
const threeCalibersRule =
|
||||||
|
shell.caliber > thickness * 3 || layerIndex > 0;
|
||||||
|
const twoCalibersRule = shell.caliber > thickness * 2;
|
||||||
|
const finalNormalization = twoCalibersRule
|
||||||
|
? (1.4 * normalization * shell.caliber) /
|
||||||
|
(2.0 * thickness)
|
||||||
|
: normalization;
|
||||||
|
const finalThickness =
|
||||||
|
thickness === 0
|
||||||
|
? 0
|
||||||
|
: thickness /
|
||||||
|
Math.cos(Math.max(0, angle - finalNormalization));
|
||||||
|
|
||||||
|
if (!threeCalibersRule && angle >= ricochet) {
|
||||||
|
shot.layers.push({
|
||||||
|
type,
|
||||||
|
index: layerIndex,
|
||||||
|
shellNormal,
|
||||||
|
surfaceNormal,
|
||||||
|
point: intersection.point,
|
||||||
|
thickness,
|
||||||
|
thicknessAngled: finalThickness,
|
||||||
|
angle,
|
||||||
|
status: 'ricochet',
|
||||||
|
});
|
||||||
|
|
||||||
|
remainingPenetration *= 0.75;
|
||||||
|
|
||||||
|
const raycaster = new Raycaster();
|
||||||
|
const newShellNormal = shellNormal
|
||||||
|
.clone()
|
||||||
|
.reflect(surfaceNormal);
|
||||||
|
const newCameraNormal = newShellNormal
|
||||||
|
.clone()
|
||||||
|
.multiplyScalar(-1);
|
||||||
|
|
||||||
|
raycaster.set(intersection.point, newCameraNormal);
|
||||||
|
pushLogs(
|
||||||
|
newShellNormal,
|
||||||
|
filterIntersections(
|
||||||
|
raycaster.intersectObjects(scene.children, true),
|
||||||
|
),
|
||||||
|
layerIndex + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
remainingPenetration -= finalThickness;
|
||||||
|
const blocked = remainingPenetration < 0;
|
||||||
|
|
||||||
|
shot.layers.push({
|
||||||
|
type,
|
||||||
|
index: layerIndex,
|
||||||
|
shellNormal,
|
||||||
|
surfaceNormal,
|
||||||
|
point: intersection.point,
|
||||||
|
thickness,
|
||||||
|
thicknessAngled: finalThickness,
|
||||||
|
angle,
|
||||||
|
status: blocked ? 'blocked' : 'penetration',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layerIndex++;
|
||||||
|
loopIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
layerIndex++;
|
|
||||||
loopIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
useTankopediaTemporary.setState({ shot });
|
useTankopediaTemporary.setState({ shot });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})}
|
node.uuid,
|
||||||
|
)}
|
||||||
|
|
||||||
{props.type === ArmorType.Spaced && (
|
{props.type === ArmorType.Spaced && (
|
||||||
<SpacedArmorSubSpaced node={node} thickness={thickness} />
|
<SpacedArmorSubSpaced node={node} thickness={thickness} />
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export function CrewSkillManager({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GenericTankComponentButton
|
<GenericTankComponentButton
|
||||||
|
key={skill}
|
||||||
special={!permanentSkills.includes(skill)}
|
special={!permanentSkills.includes(skill)}
|
||||||
first
|
first
|
||||||
last
|
last
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export default function Navbar() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LinkRadix
|
<LinkRadix
|
||||||
|
key={tool.id}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
href={`/tools/${tool.id}`}
|
href={`/tools/${tool.id}`}
|
||||||
onClick={(event) => event.preventDefault()}
|
onClick={(event) => event.preventDefault()}
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
export function Google() {
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
export function Party3() {
|
||||||
|
useEffect(() => {
|
||||||
|
(window as any).msAdsQueue = (window as any).msAdsQueue || [];
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* analytics */}
|
{/* analytics */}
|
||||||
<script
|
<script
|
||||||
async
|
async
|
||||||
src="https://www.googletagmanager.com/gtag/js?id=G-98NTMRHRP9"
|
src="https://www.googletagmanager.com/gtag/js?id=G-D8DT6EWVFJ"
|
||||||
/>
|
/>
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
@@ -13,7 +19,7 @@ export function Google() {
|
|||||||
function gtag(){dataLayer.push(arguments);}
|
function gtag(){dataLayer.push(arguments);}
|
||||||
gtag('js', new Date());
|
gtag('js', new Date());
|
||||||
|
|
||||||
gtag('config', 'G-98NTMRHRP9');
|
gtag('config', 'G-D8DT6EWVFJ');
|
||||||
`,
|
`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -24,6 +30,13 @@ export function Google() {
|
|||||||
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1289406790225052"
|
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1289406790225052"
|
||||||
crossOrigin="anonymous"
|
crossOrigin="anonymous"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* pub center */}
|
||||||
|
{/* <script
|
||||||
|
async
|
||||||
|
src="https://adsdk.microsoft.com/pubcenter/sdk.js?siteId=364477&publisherId=253617120"
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
/> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -65,5 +65,6 @@ export default async function commitMultipleFiles(
|
|||||||
repo,
|
repo,
|
||||||
ref: `heads/${branch}`,
|
ref: `heads/${branch}`,
|
||||||
sha: newCommitData.sha,
|
sha: newCommitData.sha,
|
||||||
|
force: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -430,8 +430,12 @@ export function tankCharacteristics(
|
|||||||
const height = size[0];
|
const height = size[0];
|
||||||
const length = size[1];
|
const length = size[1];
|
||||||
const volume = width * height * length;
|
const volume = width * height * length;
|
||||||
|
const shellNormalization = shell.normalization ?? 0;
|
||||||
|
const shellRicochet = shell.ricochet;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
shellNormalization,
|
||||||
|
shellRicochet,
|
||||||
dpm,
|
dpm,
|
||||||
dpmMaximum,
|
dpmMaximum,
|
||||||
dpmEffective,
|
dpmEffective,
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { asset } from './asset';
|
||||||
|
|
||||||
|
export interface VideoDefinitions {
|
||||||
|
[id: number]: {
|
||||||
|
videos: string[];
|
||||||
|
lastUpdated: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const videoDefinitions = fetch(asset('definitions/videos.csv'))
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) =>
|
||||||
|
text
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => {
|
||||||
|
const [idString, lastUpdatedString, ...videos] = line.split(',');
|
||||||
|
const id = Number(idString);
|
||||||
|
const lastUpdated = Number(lastUpdatedString);
|
||||||
|
return { id, videos, lastUpdated };
|
||||||
|
})
|
||||||
|
.filter(({ videos }) => videos.length > 0)
|
||||||
|
.reduce<VideoDefinitions>((accumulator, { id, videos, lastUpdated }) => {
|
||||||
|
accumulator[id] = {
|
||||||
|
videos,
|
||||||
|
lastUpdated,
|
||||||
|
};
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}, {}),
|
||||||
|
);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { sumBy } from 'lodash';
|
||||||
|
import { use, useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
TankDefinition,
|
||||||
|
tankDefinitions,
|
||||||
|
} from '../core/blitzkrieg/tankDefinitions';
|
||||||
|
import { useDuel } from '../stores/duel';
|
||||||
|
|
||||||
|
export enum UseEccentricityMode {
|
||||||
|
Tier,
|
||||||
|
Class,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useEccentricity(mode: UseEccentricityMode) {
|
||||||
|
const awaitedTankDefinitions = use(tankDefinitions);
|
||||||
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
|
const similarTanks = useMemo(
|
||||||
|
() =>
|
||||||
|
Object.values(awaitedTankDefinitions).filter(
|
||||||
|
(tankB) =>
|
||||||
|
tank.tier === tankB.tier &&
|
||||||
|
(mode === UseEccentricityMode.Class
|
||||||
|
? tank.class === tankB.class
|
||||||
|
: true),
|
||||||
|
),
|
||||||
|
[tank.id],
|
||||||
|
);
|
||||||
|
|
||||||
|
function eccentricity(property: (tank: TankDefinition) => number) {
|
||||||
|
const average = sumBy(similarTanks, property) / similarTanks.length;
|
||||||
|
return property(tank) / average;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eccentricity;
|
||||||
|
}
|
||||||
@@ -2590,6 +2590,13 @@ acorn@^8.11.3:
|
|||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
|
||||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||||
|
|
||||||
|
agent-base@^7.0.2:
|
||||||
|
version "7.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317"
|
||||||
|
integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.3.4"
|
||||||
|
|
||||||
aggregate-error@^3.0.0:
|
aggregate-error@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
|
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
|
||||||
@@ -2691,7 +2698,7 @@ [email protected]:
|
|||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
||||||
integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==
|
integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==
|
||||||
|
|
||||||
base64-js@^1.3.1, base64-js@^1.5.1:
|
base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
@@ -2718,6 +2725,11 @@ big.js@^5.2.2:
|
|||||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||||
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
|
||||||
|
|
||||||
|
bignumber.js@^9.0.0:
|
||||||
|
version "9.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c"
|
||||||
|
integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==
|
||||||
|
|
||||||
bl@^1.0.0:
|
bl@^1.0.0:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
|
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
|
||||||
@@ -2807,6 +2819,11 @@ buffer-crc32@~0.2.3:
|
|||||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||||
integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
|
integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||||
|
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
|
||||||
|
|
||||||
buffer-fill@^1.0.0:
|
buffer-fill@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||||
@@ -2852,7 +2869,7 @@ cac@^6.7.14:
|
|||||||
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
|
||||||
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
|
||||||
|
|
||||||
call-bind@^1.0.6:
|
call-bind@^1.0.6, call-bind@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||||
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
||||||
@@ -3101,7 +3118,7 @@ [email protected]:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
debug@^4.1.0, debug@^4.3.1, debug@^4.3.4:
|
debug@4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4:
|
||||||
version "4.3.4"
|
version "4.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||||
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
|
||||||
@@ -3273,6 +3290,13 @@ [email protected]:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
wcwidth "^1.0.1"
|
wcwidth "^1.0.1"
|
||||||
|
|
||||||
|
[email protected], ecdsa-sig-formatter@^1.0.11:
|
||||||
|
version "1.0.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
|
||||||
|
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
|
||||||
|
dependencies:
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||||
@@ -3450,6 +3474,11 @@ express@^4.18.2:
|
|||||||
utils-merge "1.0.1"
|
utils-merge "1.0.1"
|
||||||
vary "~1.1.2"
|
vary "~1.1.2"
|
||||||
|
|
||||||
|
extend@^3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||||
|
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||||
|
|
||||||
"false@^0.0.4":
|
"false@^0.0.4":
|
||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/false/-/false-0.0.4.tgz#8f55de5af5c03f50bf68aed57ed80e3d2176a517"
|
resolved "https://registry.yarnpkg.com/false/-/false-0.0.4.tgz#8f55de5af5c03f50bf68aed57ed80e3d2176a517"
|
||||||
@@ -3629,6 +3658,25 @@ fuzzysort@^2.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84"
|
resolved "https://registry.yarnpkg.com/fuzzysort/-/fuzzysort-2.0.4.tgz#a21d1ce8947eaf2797dc3b7c28c36db9d1165f84"
|
||||||
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
integrity sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==
|
||||||
|
|
||||||
|
gaxios@^6.0.0, gaxios@^6.0.3, gaxios@^6.1.1:
|
||||||
|
version "6.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-6.5.0.tgz#21bc20e24f21189ce8907079b56205ff9fd2c0d7"
|
||||||
|
integrity sha512-R9QGdv8j4/dlNoQbX3hSaK/S0rkMijqjVvW3YM06CoBdbU/VdKd159j4hePpng0KuE6Lh6JJ7UdmVGJZFcAG1w==
|
||||||
|
dependencies:
|
||||||
|
extend "^3.0.2"
|
||||||
|
https-proxy-agent "^7.0.1"
|
||||||
|
is-stream "^2.0.0"
|
||||||
|
node-fetch "^2.6.9"
|
||||||
|
uuid "^9.0.1"
|
||||||
|
|
||||||
|
gcp-metadata@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-6.1.0.tgz#9b0dd2b2445258e7597f2024332d20611cbd6b8c"
|
||||||
|
integrity sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==
|
||||||
|
dependencies:
|
||||||
|
gaxios "^6.0.0"
|
||||||
|
json-bigint "^1.0.0"
|
||||||
|
|
||||||
gensync@^1.0.0-beta.2:
|
gensync@^1.0.0-beta.2:
|
||||||
version "1.0.0-beta.2"
|
version "1.0.0-beta.2"
|
||||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||||
@@ -3710,6 +3758,38 @@ glsl-noise@^0.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/glsl-noise/-/glsl-noise-0.0.0.tgz#367745f3a33382c0eeec4cb54b7e99cfc1d7670b"
|
resolved "https://registry.yarnpkg.com/glsl-noise/-/glsl-noise-0.0.0.tgz#367745f3a33382c0eeec4cb54b7e99cfc1d7670b"
|
||||||
integrity sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==
|
integrity sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==
|
||||||
|
|
||||||
|
google-auth-library@^9.0.0, google-auth-library@^9.7.0:
|
||||||
|
version "9.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-9.8.0.tgz#43ae0f72dd72f49fd6a4a46d8eeffe2236691b20"
|
||||||
|
integrity sha512-TJJXFzMlVGRlIH27gYZ6XXyPf5Y3OItsKFfefsDAafNNywYRTkei83nEO29IrYj8GtdHWU78YnW+YZdaZaXIJA==
|
||||||
|
dependencies:
|
||||||
|
base64-js "^1.3.0"
|
||||||
|
ecdsa-sig-formatter "^1.0.11"
|
||||||
|
gaxios "^6.1.1"
|
||||||
|
gcp-metadata "^6.1.0"
|
||||||
|
gtoken "^7.0.0"
|
||||||
|
jws "^4.0.0"
|
||||||
|
|
||||||
|
googleapis-common@^7.0.0:
|
||||||
|
version "7.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/googleapis-common/-/googleapis-common-7.1.0.tgz#e97e468a7ef2f230df8255c0f66701cf7e28947c"
|
||||||
|
integrity sha512-p3KHiWDBBWJEXk6SYauBEvxw5+UmRy7k2scxGtsNv9eHsTbpopJ3/7If4OrNnzJ9XMLg3IlyQXpVp8YPQsStiw==
|
||||||
|
dependencies:
|
||||||
|
extend "^3.0.2"
|
||||||
|
gaxios "^6.0.3"
|
||||||
|
google-auth-library "^9.7.0"
|
||||||
|
qs "^6.7.0"
|
||||||
|
url-template "^2.0.8"
|
||||||
|
uuid "^9.0.0"
|
||||||
|
|
||||||
|
googleapis@^134.0.0:
|
||||||
|
version "134.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-134.0.0.tgz#1cde101a00916c677384b76bcd0eea57cf3f80bd"
|
||||||
|
integrity sha512-o8LhD1754W6MHWtpwAPeP1WUHgNxuMxCnLMDFlMKAA5kCMTNqX9/eaTXnkkAIv6YRfoKMQ6D1vyR6/biXuhE9g==
|
||||||
|
dependencies:
|
||||||
|
google-auth-library "^9.0.0"
|
||||||
|
googleapis-common "^7.0.0"
|
||||||
|
|
||||||
gopd@^1.0.1:
|
gopd@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
||||||
@@ -3722,6 +3802,14 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0
|
|||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||||
|
|
||||||
|
gtoken@^7.0.0:
|
||||||
|
version "7.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-7.1.0.tgz#d61b4ebd10132222817f7222b1e6064bd463fc26"
|
||||||
|
integrity sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==
|
||||||
|
dependencies:
|
||||||
|
gaxios "^6.0.0"
|
||||||
|
jws "^4.0.0"
|
||||||
|
|
||||||
has-flag@^3.0.0:
|
has-flag@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||||
@@ -3796,6 +3884,14 @@ [email protected]:
|
|||||||
statuses "2.0.1"
|
statuses "2.0.1"
|
||||||
toidentifier "1.0.1"
|
toidentifier "1.0.1"
|
||||||
|
|
||||||
|
https-proxy-agent@^7.0.1:
|
||||||
|
version "7.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168"
|
||||||
|
integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==
|
||||||
|
dependencies:
|
||||||
|
agent-base "^7.0.2"
|
||||||
|
debug "4"
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
@@ -3917,6 +4013,11 @@ is-stream@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||||
integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
|
integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
|
||||||
|
|
||||||
|
is-stream@^2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
|
||||||
|
integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
|
||||||
|
|
||||||
isarray@~1.0.0:
|
isarray@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||||
@@ -3980,6 +4081,13 @@ jsesc@^2.5.1:
|
|||||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
|
||||||
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
|
||||||
|
|
||||||
|
json-bigint@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1"
|
||||||
|
integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==
|
||||||
|
dependencies:
|
||||||
|
bignumber.js "^9.0.0"
|
||||||
|
|
||||||
json-parse-even-better-errors@^2.3.0:
|
json-parse-even-better-errors@^2.3.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
|
||||||
@@ -4014,6 +4122,23 @@ jsonfile@^6.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
|
jwa@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
|
||||||
|
integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
|
||||||
|
dependencies:
|
||||||
|
buffer-equal-constant-time "1.0.1"
|
||||||
|
ecdsa-sig-formatter "1.0.11"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
jws@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
|
||||||
|
integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
|
||||||
|
dependencies:
|
||||||
|
jwa "^2.0.0"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
knip@^3.4.0:
|
knip@^3.4.0:
|
||||||
version "3.13.2"
|
version "3.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/knip/-/knip-3.13.2.tgz#34f347a9b3ff1d45f3be7fed6bd3bb1ee5fbbaaa"
|
resolved "https://registry.yarnpkg.com/knip/-/knip-3.13.2.tgz#34f347a9b3ff1d45f3be7fed6bd3bb1ee5fbbaaa"
|
||||||
@@ -4397,6 +4522,13 @@ [email protected]:
|
|||||||
data-uri-to-buffer "^3.0.1"
|
data-uri-to-buffer "^3.0.1"
|
||||||
fetch-blob "^2.1.1"
|
fetch-blob "^2.1.1"
|
||||||
|
|
||||||
|
node-fetch@^2.6.9:
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||||
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
|
dependencies:
|
||||||
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
node-releases@^2.0.14:
|
node-releases@^2.0.14:
|
||||||
version "2.0.14"
|
version "2.0.14"
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
|
||||||
@@ -4772,6 +4904,13 @@ [email protected]:
|
|||||||
dependencies:
|
dependencies:
|
||||||
side-channel "^1.0.4"
|
side-channel "^1.0.4"
|
||||||
|
|
||||||
|
qs@^6.7.0:
|
||||||
|
version "6.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a"
|
||||||
|
integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==
|
||||||
|
dependencies:
|
||||||
|
side-channel "^1.0.6"
|
||||||
|
|
||||||
queue-microtask@^1.2.2:
|
queue-microtask@^1.2.2:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
@@ -5011,7 +5150,7 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
[email protected], safe-buffer@^5.1.1, safe-buffer@~5.2.0:
|
[email protected], safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.2.0:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||||
@@ -5184,6 +5323,16 @@ side-channel@^1.0.4:
|
|||||||
get-intrinsic "^1.2.4"
|
get-intrinsic "^1.2.4"
|
||||||
object-inspect "^1.13.1"
|
object-inspect "^1.13.1"
|
||||||
|
|
||||||
|
side-channel@^1.0.6:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||||
|
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
|
||||||
|
dependencies:
|
||||||
|
call-bind "^1.0.7"
|
||||||
|
es-errors "^1.3.0"
|
||||||
|
get-intrinsic "^1.2.4"
|
||||||
|
object-inspect "^1.13.1"
|
||||||
|
|
||||||
signal-exit@^4.0.1:
|
signal-exit@^4.0.1:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||||
@@ -5480,6 +5629,11 @@ [email protected]:
|
|||||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||||
|
|
||||||
|
tr46@~0.0.3:
|
||||||
|
version "0.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
troika-three-text@^0.49.0:
|
troika-three-text@^0.49.0:
|
||||||
version "0.49.0"
|
version "0.49.0"
|
||||||
resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.49.0.tgz#bc2dc1924250c477cd39316cd83585dee12550e0"
|
resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.49.0.tgz#bc2dc1924250c477cd39316cd83585dee12550e0"
|
||||||
@@ -5615,6 +5769,11 @@ update-browserslist-db@^1.0.13:
|
|||||||
escalade "^3.1.1"
|
escalade "^3.1.1"
|
||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
|
|
||||||
|
url-template@^2.0.8:
|
||||||
|
version "2.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
|
||||||
|
integrity sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==
|
||||||
|
|
||||||
use-callback-ref@^1.3.0:
|
use-callback-ref@^1.3.0:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0"
|
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.1.tgz#9be64c3902cbd72b07fe55e56408ae3a26036fd0"
|
||||||
@@ -5650,7 +5809,7 @@ [email protected]:
|
|||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||||
|
|
||||||
uuid@^9.0.1:
|
uuid@^9.0.0, uuid@^9.0.1:
|
||||||
version "9.0.1"
|
version "9.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||||
@@ -5787,6 +5946,19 @@ [email protected]:
|
|||||||
resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd"
|
resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd"
|
||||||
integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==
|
integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==
|
||||||
|
|
||||||
|
webidl-conversions@^3.0.0:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||||
|
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
|
||||||
|
|
||||||
|
whatwg-url@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||||
|
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
|
||||||
|
dependencies:
|
||||||
|
tr46 "~0.0.3"
|
||||||
|
webidl-conversions "^3.0.0"
|
||||||
|
|
||||||
which@^2.0.1:
|
which@^2.0.1:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||||
|
|||||||