mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8edd16eb3 | ||
|
|
b96ff2e239 | ||
|
|
a575da3005 | ||
|
|
3ca2dece3e | ||
|
|
191d6133b2 | ||
|
|
b15e73e3a8 | ||
|
|
9a6b8ab979 | ||
|
|
87786d41a7 | ||
|
|
ee7ffe7bc8 | ||
|
|
379a33375d | ||
|
|
bd3f5dea05 | ||
|
|
146d36234e | ||
|
|
f3edcb8077 | ||
|
|
9e492015ff | ||
|
|
d2977182d9 | ||
|
|
7d2d65bab8 | ||
|
|
415c3bd066 |
No files matched your search
@@ -4,7 +4,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * *'
|
- cron: '0 2 * * *'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Install Yarn
|
||||||
|
run: npm install --location=global yarn
|
||||||
|
|
||||||
|
- name: Add fixed sharp
|
||||||
|
run: yarn add [email protected] --ignore-engines
|
||||||
|
|
||||||
- name: Download release assets
|
- name: Download release assets
|
||||||
run: |
|
run: |
|
||||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/tresabhi/blitzkrieg/releases/latest \
|
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/tresabhi/blitzkrieg/releases/latest \
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn
|
run: yarn
|
||||||
|
|
||||||
|
- name: Add fixed sharp
|
||||||
|
run: yarn add [email protected] --ignore-engines
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn build:bot
|
run: yarn build:bot
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Blitzkrieg 1.17.1
|
||||||
|
|
||||||
|
Some stability fixes.
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- `sharp` is now included in the build instead of having being installed before runtime.
|
||||||
|
- Png converter cache is now more memory efficient.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Blitzkrieg 1.17.2
|
||||||
|
|
||||||
|
Introducing the new `/research` command!
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added the `/research` command
|
||||||
|
- Type in the name of a tech tree tank you desire to research and this command will list all the expenses in researching all tanks in that line
|
||||||
|
- The starting tank is inferred automatically by the tanks you own
|
||||||
|
- This may be a bit inaccurate because of the lack of accurate information Wargaming provides about owned tanks
|
||||||
|
- You are also manually provide a starting tank and a user to see the progress on a line for
|
||||||
|
- Replaced Vercel Analytics (which collapsed under the insane amount of traffic on the website) with Google Analytics
|
||||||
|
- Spaced armor can now be toggled in the Tankopedia armor sandbox
|
||||||
+2
-3
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkrieg",
|
"name": "blitzkrieg",
|
||||||
"version": "1.17.0",
|
"version": "1.17.1",
|
||||||
"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",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"build:assets": "vite-node --max_old_space_size=16384 --script scripts/buildAssets/index",
|
"build:assets": "vite-node --max_old_space_size=16384 --script scripts/buildAssets/index",
|
||||||
"build:test": "vite-node --script scripts/buildTest",
|
"build:test": "vite-node --script scripts/buildTest",
|
||||||
"build:ratingsplot": "vite-node --script scripts/buildRatingsPlot",
|
"build:ratingsplot": "vite-node --script scripts/buildRatingsPlot",
|
||||||
"dev:bot": "yarn build:bot && yarn start:bot",
|
"dev:bot": "yarn build:bot --dev && yarn start:bot",
|
||||||
"dev:docs": "vitepress dev docs",
|
"dev:docs": "vitepress dev docs",
|
||||||
"dev:website": "next dev",
|
"dev:website": "next dev",
|
||||||
"start:bot": "node --enable-source-maps dist/bot/index.cjs",
|
"start:bot": "node --enable-source-maps dist/bot/index.cjs",
|
||||||
@@ -43,7 +43,6 @@
|
|||||||
"@resvg/resvg-js": "^2.4.1",
|
"@resvg/resvg-js": "^2.4.1",
|
||||||
"@types/three": "^0.160.0",
|
"@types/three": "^0.160.0",
|
||||||
"@vanilla-extract/css": "^1.13.0",
|
"@vanilla-extract/css": "^1.13.0",
|
||||||
"@vercel/analytics": "^1.2.2",
|
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
"decompress": "^4.2.1",
|
"decompress": "^4.2.1",
|
||||||
"discord.js": "^14.13.0",
|
"discord.js": "^14.13.0",
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { build } from 'esbuild';
|
import { build } from 'esbuild';
|
||||||
import { cp, readdir } from 'fs/promises';
|
import { cp, readdir } from 'fs/promises';
|
||||||
|
import { argv } from 'process';
|
||||||
|
|
||||||
|
const isDev = argv.includes('--dev');
|
||||||
|
|
||||||
readdir('src/workers').then((workers) => {
|
readdir('src/workers').then((workers) => {
|
||||||
const files = [
|
const files = [
|
||||||
@@ -25,6 +28,7 @@ readdir('src/workers').then((workers) => {
|
|||||||
'.js': '.cjs',
|
'.js': '.cjs',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
external: ['sharp'],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
minifyIdentifiers: false, // causes goofy errors
|
minifyIdentifiers: false, // causes goofy errors
|
||||||
|
|||||||
+2
-3
@@ -3,12 +3,12 @@
|
|||||||
import { CaretRightIcon } from '@radix-ui/react-icons';
|
import { CaretRightIcon } from '@radix-ui/react-icons';
|
||||||
import { AlertDialog, Button, Flex, Text, Theme } from '@radix-ui/themes';
|
import { AlertDialog, Button, Flex, Text, Theme } from '@radix-ui/themes';
|
||||||
import '@radix-ui/themes/styles.css';
|
import '@radix-ui/themes/styles.css';
|
||||||
import { Analytics } from '@vercel/analytics/react';
|
|
||||||
import { config } from 'dotenv';
|
import { config } from 'dotenv';
|
||||||
import { Roboto_Flex } from 'next/font/google';
|
import { Roboto_Flex } from 'next/font/google';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { ReactNode, useEffect, useState } from 'react';
|
import { ReactNode, useEffect, useState } from 'react';
|
||||||
import { SkyLine } from '../assets/art/SkyLine';
|
import { SkyLine } from '../assets/art/SkyLine';
|
||||||
|
import { Analytics } from '../components/Analytics';
|
||||||
import Navbar from '../components/Navbar';
|
import Navbar from '../components/Navbar';
|
||||||
import PageWrapper from '../components/PageWrapper';
|
import PageWrapper from '../components/PageWrapper';
|
||||||
import isDev from '../core/blitzkrieg/isDev';
|
import isDev from '../core/blitzkrieg/isDev';
|
||||||
@@ -51,6 +51,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
|||||||
name="description"
|
name="description"
|
||||||
content="🎉 Tools for everything World of Tanks Blitz"
|
content="🎉 Tools for everything World of Tanks Blitz"
|
||||||
/>
|
/>
|
||||||
|
<Analytics />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body
|
<body
|
||||||
@@ -60,8 +61,6 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
|||||||
backgroundColor: isEmbed ? 'transparent' : undefined,
|
backgroundColor: isEmbed ? 'transparent' : undefined,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Analytics />
|
|
||||||
|
|
||||||
<Theme
|
<Theme
|
||||||
appearance="dark"
|
appearance="dark"
|
||||||
panelBackground="translucent"
|
panelBackground="translucent"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Button, DropdownMenu, Flex } from '@radix-ui/themes';
|
|||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
import { Pose, poseEvent } from '../../../../../../../core/blitzkrieg/pose';
|
import { Pose, poseEvent } from '../../../../../../../core/blitzkrieg/pose';
|
||||||
import mutateTankopediaPersistent, {
|
import mutateTankopediaPersistent, {
|
||||||
|
mutateTankopediaTemporary,
|
||||||
useTankopediaPersistent,
|
useTankopediaPersistent,
|
||||||
} from '../../../../../../../stores/tankopedia';
|
} from '../../../../../../../stores/tankopedia';
|
||||||
import { ENVIRONMENTS } from '../../Lighting';
|
import { ENVIRONMENTS } from '../../Lighting';
|
||||||
@@ -30,6 +31,9 @@ export function Options({ isFullScreen, canvasWrapper }: OptionsProps) {
|
|||||||
const wireframe = useTankopediaPersistent(
|
const wireframe = useTankopediaPersistent(
|
||||||
(state) => state.model.visual.wireframe,
|
(state) => state.model.visual.wireframe,
|
||||||
);
|
);
|
||||||
|
const showSpacedArmor = useTankopediaPersistent(
|
||||||
|
(state) => state.model.visual.showSpacedArmor,
|
||||||
|
);
|
||||||
const opaque = useTankopediaPersistent((state) => state.model.visual.opaque);
|
const opaque = useTankopediaPersistent((state) => state.model.visual.opaque);
|
||||||
const fullScreenAvailable =
|
const fullScreenAvailable =
|
||||||
typeof document !== 'undefined' && document.fullscreenEnabled;
|
typeof document !== 'undefined' && document.fullscreenEnabled;
|
||||||
@@ -81,6 +85,20 @@ export function Options({ isFullScreen, canvasWrapper }: OptionsProps) {
|
|||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
<DropdownMenu.Label>Armor</DropdownMenu.Label>
|
<DropdownMenu.Label>Armor</DropdownMenu.Label>
|
||||||
|
|
||||||
|
<DropdownMenu.CheckboxItem
|
||||||
|
checked={showSpacedArmor}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
mutateTankopediaPersistent((draft) => {
|
||||||
|
draft.model.visual.showSpacedArmor = checked;
|
||||||
|
});
|
||||||
|
mutateTankopediaTemporary((draft) => {
|
||||||
|
draft.shot = undefined;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Spaced armor
|
||||||
|
</DropdownMenu.CheckboxItem>
|
||||||
|
|
||||||
<DropdownMenu.CheckboxItem
|
<DropdownMenu.CheckboxItem
|
||||||
checked={greenPenetration}
|
checked={greenPenetration}
|
||||||
onCheckedChange={(checked) => {
|
onCheckedChange={(checked) => {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
} from '../core/blitzkrieg/tankDefinitions/constants';
|
} from '../core/blitzkrieg/tankDefinitions/constants';
|
||||||
import { tankIconPng } from '../core/blitzkrieg/tankIconPng';
|
import { tankIconPng } from '../core/blitzkrieg/tankIconPng';
|
||||||
|
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
||||||
import autocompleteTanks from '../core/discord/autocompleteTanks';
|
import autocompleteTanks from '../core/discord/autocompleteTanks';
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from '../core/discord/localizationObject';
|
||||||
@@ -31,7 +32,6 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
resolve({
|
resolve({
|
||||||
inProduction: true,
|
inProduction: true,
|
||||||
inPublic: true,
|
inPublic: true,
|
||||||
inPreview: true,
|
|
||||||
|
|
||||||
command: createLocalizedCommand('research')
|
command: createLocalizedCommand('research')
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
@@ -67,7 +67,8 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
)
|
)
|
||||||
.setAutocomplete(true)
|
.setAutocomplete(true)
|
||||||
.setRequired(false),
|
.setRequired(false),
|
||||||
),
|
)
|
||||||
|
.addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { t, translate } = translator(interaction.locale);
|
const { t, translate } = translator(interaction.locale);
|
||||||
@@ -285,8 +286,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Experience:{' '}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + b.purchase + b.equipment, 0)
|
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -309,8 +311,34 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Purchase:{' '}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
.reduce((a, b) => a + b.purchase, 0)
|
||||||
|
.toLocaleString(interaction.locale)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 4,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={await iconPng(asset('icons/currencies/silver.webp'))}
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: theme.colors.textHighContrast,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Equipment:{' '}
|
||||||
|
{costs
|
||||||
|
.reduce((a, b) => a + b.equipment, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
export function Analytics() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
src="https://www.googletagmanager.com/gtag/js?id=G-98NTMRHRP9"
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
|
function gtag(){dataLayer.push(arguments);}
|
||||||
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-98NTMRHRP9');
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ export function CoreArmorSceneComponent({
|
|||||||
explosionRadius: { value: null },
|
explosionRadius: { value: null },
|
||||||
greenPenetration: { value: null },
|
greenPenetration: { value: null },
|
||||||
opaque: { value: null },
|
opaque: { value: null },
|
||||||
|
useSpacedArmor: { value: null },
|
||||||
|
|
||||||
resolution: { value: new Vector2() },
|
resolution: { value: new Vector2() },
|
||||||
spacedArmorBuffer: { value: null },
|
spacedArmorBuffer: { value: null },
|
||||||
@@ -75,6 +76,7 @@ export function CoreArmorSceneComponent({
|
|||||||
) {
|
) {
|
||||||
material.uniforms.greenPenetration.value = visual.greenPenetration;
|
material.uniforms.greenPenetration.value = visual.greenPenetration;
|
||||||
material.uniforms.opaque.value = visual.opaque || visual.wireframe;
|
material.uniforms.opaque.value = visual.opaque || visual.wireframe;
|
||||||
|
material.uniforms.useSpacedArmor.value = visual.showSpacedArmor;
|
||||||
material.wireframe = visual.wireframe;
|
material.wireframe = visual.wireframe;
|
||||||
}
|
}
|
||||||
async function handleProtagonistEquipmentChange(
|
async function handleProtagonistEquipmentChange(
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ uniform float damage;
|
|||||||
uniform float explosionRadius;
|
uniform float explosionRadius;
|
||||||
uniform bool greenPenetration;
|
uniform bool greenPenetration;
|
||||||
uniform bool opaque;
|
uniform bool opaque;
|
||||||
|
uniform bool useSpacedArmor;
|
||||||
|
|
||||||
uniform highp sampler2D spacedArmorBuffer;
|
uniform highp sampler2D spacedArmorBuffer;
|
||||||
uniform highp sampler2D spacedArmorDepth;
|
uniform highp sampler2D spacedArmorDepth;
|
||||||
@@ -49,7 +50,7 @@ void main() {
|
|||||||
float coreArmorDistance = depthToDistance(gl_FragCoord.z);
|
float coreArmorDistance = depthToDistance(gl_FragCoord.z);
|
||||||
float distanceFromSpacedArmor = coreArmorDistance - spacedArmorDistance;
|
float distanceFromSpacedArmor = coreArmorDistance - spacedArmorDistance;
|
||||||
|
|
||||||
if (isUnderSpacedArmor) {
|
if (useSpacedArmor && isUnderSpacedArmor) {
|
||||||
float spacedArmorThickness = spacedArmorBufferFragment.r * penetration;
|
float spacedArmorThickness = spacedArmorBufferFragment.r * penetration;
|
||||||
remainingPenetration -= spacedArmorThickness;
|
remainingPenetration -= spacedArmorThickness;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { useDuel } from '../../../../stores/duel';
|
|||||||
import {
|
import {
|
||||||
Shot,
|
Shot,
|
||||||
ShotLayerBase,
|
ShotLayerBase,
|
||||||
|
useTankopediaPersistent,
|
||||||
useTankopediaTemporary,
|
useTankopediaTemporary,
|
||||||
} from '../../../../stores/tankopedia';
|
} from '../../../../stores/tankopedia';
|
||||||
import { ArmorType } from '../SpacedArmorScene';
|
import { ArmorType } from '../SpacedArmorScene';
|
||||||
@@ -115,12 +116,20 @@ export function SpacedArmorSceneComponent({
|
|||||||
pushLogs(shellNormal, filterIntersections(event.intersections), 0);
|
pushLogs(shellNormal, filterIntersections(event.intersections), 0);
|
||||||
|
|
||||||
function filterIntersections(intersectionsRaw: Intersection[]) {
|
function filterIntersections(intersectionsRaw: Intersection[]) {
|
||||||
const intersectionsAll = intersectionsRaw.filter(
|
const showSpacedArmor =
|
||||||
|
useTankopediaPersistent.getState().model.visual.showSpacedArmor;
|
||||||
|
const intersectionsTyped = intersectionsRaw.filter(
|
||||||
({ object }) => object.userData.type !== undefined,
|
({ object }) => object.userData.type !== undefined,
|
||||||
) as ArmorMeshIntersection[];
|
) as ArmorMeshIntersection[];
|
||||||
const intersectionsWithDuplicates = intersectionsAll.slice(
|
const intersectionsFiltered = intersectionsTyped.filter(
|
||||||
|
({ object }) =>
|
||||||
|
showSpacedArmor
|
||||||
|
? true
|
||||||
|
: object.userData.type === ArmorType.Core,
|
||||||
|
);
|
||||||
|
const intersectionsWithDuplicates = intersectionsFiltered.slice(
|
||||||
0,
|
0,
|
||||||
intersectionsAll.findIndex(
|
intersectionsFiltered.findIndex(
|
||||||
({ object }) => object.userData.type === ArmorType.Core,
|
({ object }) => object.userData.type === ArmorType.Core,
|
||||||
) + 1,
|
) + 1,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export async function extractModel(data: string, path: string) {
|
|||||||
material.setBaseColorTexture(
|
material.setBaseColorTexture(
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType('image/png')
|
.setMimeType('image/jpeg')
|
||||||
.setImage(
|
.setImage(
|
||||||
await readTexture(
|
await readTexture(
|
||||||
`${data}/3d/${dirname(path)}/${textures.albedo}`,
|
`${data}/3d/${dirname(path)}/${textures.albedo}`,
|
||||||
@@ -70,7 +70,7 @@ export async function extractModel(data: string, path: string) {
|
|||||||
material.setMetallicRoughnessTexture(
|
material.setMetallicRoughnessTexture(
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType('image/png')
|
.setMimeType('image/jpeg')
|
||||||
.setImage(
|
.setImage(
|
||||||
await readTexture(
|
await readTexture(
|
||||||
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`,
|
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`,
|
||||||
@@ -86,7 +86,7 @@ export async function extractModel(data: string, path: string) {
|
|||||||
material.setNormalTexture(
|
material.setNormalTexture(
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType('image/png')
|
.setMimeType('image/jpeg')
|
||||||
.setImage(
|
.setImage(
|
||||||
await readTexture(
|
await readTexture(
|
||||||
`${data}/3d/${dirname(path)}/${
|
`${data}/3d/${dirname(path)}/${
|
||||||
@@ -102,7 +102,7 @@ export async function extractModel(data: string, path: string) {
|
|||||||
material.setOcclusionTexture(
|
material.setOcclusionTexture(
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType('image/png')
|
.setMimeType('image/jpeg')
|
||||||
.setImage(
|
.setImage(
|
||||||
await readTexture(
|
await readTexture(
|
||||||
`${data}/3d/${dirname(path)}/${textures.miscMap}`,
|
`${data}/3d/${dirname(path)}/${textures.miscMap}`,
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
|
|
||||||
const cache: Record<string, string> = {};
|
const cache: Record<string, Buffer> = {};
|
||||||
|
|
||||||
export async function iconPng(url: string) {
|
export async function iconPng(url: string) {
|
||||||
if (cache[url]) return cache[url];
|
if (!cache[url]) {
|
||||||
|
const imageResponse = await fetch(url);
|
||||||
|
const imageBufferWEBP = await imageResponse.arrayBuffer();
|
||||||
|
const imageBufferPNG = await sharp(imageBufferWEBP).png().toBuffer();
|
||||||
|
cache[url] = imageBufferPNG;
|
||||||
|
}
|
||||||
|
|
||||||
const imageResponse = await fetch(url);
|
return `data:image/png;base64,${cache[url].toString('base64')}`;
|
||||||
const imageBufferWEBP = await imageResponse.arrayBuffer();
|
|
||||||
const imageBufferPNG = await sharp(imageBufferWEBP).png().toBuffer();
|
|
||||||
cache[url] = `data:image/png;base64,${imageBufferPNG.toString('base64')}`;
|
|
||||||
|
|
||||||
return cache[url];
|
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
|
|||||||
raw.data[index + 3] = 255;
|
raw.data[index + 3] = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await sharp(raw.data, { raw }).png().toBuffer();
|
return await sharp(raw.data, { raw }).jpeg().toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
case TextureMutation.RoughnessMetallicness: {
|
case TextureMutation.RoughnessMetallicness: {
|
||||||
@@ -45,16 +45,16 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
|
|||||||
});
|
});
|
||||||
const metallicness = sharp(raw.data, { raw })
|
const metallicness = sharp(raw.data, { raw })
|
||||||
.extractChannel('green')
|
.extractChannel('green')
|
||||||
.png()
|
.jpeg()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
const roughness = sharp(raw.data, { raw })
|
const roughness = sharp(raw.data, { raw })
|
||||||
.extractChannel('alpha')
|
.extractChannel('alpha')
|
||||||
.png()
|
.jpeg()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
return await newImage
|
return await newImage
|
||||||
.joinChannel(await Promise.all([roughness, metallicness]))
|
.joinChannel(await Promise.all([roughness, metallicness]))
|
||||||
.png()
|
.jpeg()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,15 +65,15 @@ export async function readTexture(path: string, mutation?: TextureMutation) {
|
|||||||
*/
|
*/
|
||||||
return await sharp(raw.data, { raw })
|
return await sharp(raw.data, { raw })
|
||||||
.extractChannel('alpha')
|
.extractChannel('alpha')
|
||||||
.png()
|
.jpeg()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
case TextureMutation.Albedo: {
|
case TextureMutation.Albedo: {
|
||||||
return await sharp(raw.data, { raw }).removeAlpha().png().toBuffer();
|
return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return await sharp(raw.data, { raw }).png().toBuffer();
|
return await sharp(raw.data, { raw }).jpeg().toBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -500,7 +500,7 @@
|
|||||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||||
"external_emojis": "External emojis: needed add national flags and tank class emojis"
|
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+47
-14
@@ -137,10 +137,10 @@
|
|||||||
"description": "Región"
|
"description": "Región"
|
||||||
},
|
},
|
||||||
"tier": {
|
"tier": {
|
||||||
"$": "tier",
|
"$": "nivel",
|
||||||
"description": "Tier",
|
"description": "Nivel",
|
||||||
"choices": {
|
"choices": {
|
||||||
"tier": "Tier %s - %s"
|
"tier": "Nivel %s - %s"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
"none": "Sin filtros",
|
"none": "Sin filtros",
|
||||||
"tier": "Tier %s"
|
"tier": "Nivel %s"
|
||||||
},
|
},
|
||||||
"no_data": {
|
"no_data": {
|
||||||
"battles_in_period": "No hay batallas jugadas en este período",
|
"battles_in_period": "No hay batallas jugadas en este período",
|
||||||
@@ -170,10 +170,42 @@
|
|||||||
"tank_id_not_found": "# Tanque no encontrado\nNo se pudo encontrar al tanque del ID \"%s\". Prueba escribiendo el nombre del tanque en vez de un número.",
|
"tank_id_not_found": "# Tanque no encontrado\nNo se pudo encontrar al tanque del ID \"%s\". Prueba escribiendo el nombre del tanque en vez de un número.",
|
||||||
"no_tank_stats": "# No hay estadísticas de tanque disponibles\nEste jugador no tiene estadísticas disponibles. Este podría no ser el jugador que estás buscando.",
|
"no_tank_stats": "# No hay estadísticas de tanque disponibles\nEste jugador no tiene estadísticas disponibles. Este podría no ser el jugador que estás buscando.",
|
||||||
"get_help": "Servidor de ayuda de Discord",
|
"get_help": "Servidor de ayuda de Discord",
|
||||||
"uncaught_error": "# ¡Blitzkrieg sufrió un error!\nLo sentimos mucho. Siéntete libre de [unirte al servidor oficial de Discord](https://discord.gg/nDt7AjGJQH) para obtener ayuda."
|
"uncaught_error": "# ¡Blitzkrieg sufrió un error!\nLo sentimos mucho. Siéntete libre de [unirte al servidor oficial de Discord](https://discord.gg/nDt7AjGJQH) para obtener ayuda.",
|
||||||
|
"preview": "# Este comando es una vista previa\n\nSolo puedes acceder a este comando en [el servidor oficial de Discord](https://discord.gg/nDt7AjGJQH). Generalmente este comando estará disponible pronto."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"research": {
|
||||||
|
"$": "investigar",
|
||||||
|
"description": "Enumera los gastos por investigar una línea",
|
||||||
|
"options": {
|
||||||
|
"target_tank": {
|
||||||
|
"$": "tanque-objetivo",
|
||||||
|
"description": "El último tanque a investigar en la línea"
|
||||||
|
},
|
||||||
|
"starting_tank": {
|
||||||
|
"$": "tanque-inicial",
|
||||||
|
"description": "El tanque inicial en la línea (se deduce automáticamente si no se proporciona)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"subtitle": "Investigar",
|
||||||
|
"total": "Total",
|
||||||
|
"research": "Investigar: %s",
|
||||||
|
"upgrades": "Mejoras: %s",
|
||||||
|
"purchase": "Comprar: %s",
|
||||||
|
"equipment": "Equipamiento: %s",
|
||||||
|
"estimation": "# ¡Esto es una estimación!\n\nEsta lista podría incluir tanques ya investigados debido a la información errónea que proporciona Wargaming. Si puedes, prueba proporcionando un `tanque-inicial` de la línea al usar el comando."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"non_tech_tree": "# %s no está en el árbol tecnológico\n\nNo puedes investigar un tanque prémium o coleccionista.",
|
||||||
|
"tier_1": "# %s es un nivel I\n\nLos tanque de nivel I están siempre desbloqueados gratuitamente para todos los jugadores.",
|
||||||
|
"already_researched": "# %s ya está investigado\n\nPrueba proporcionando un `tanque-inicial` al usar el comando para ver los totales para una línea que ya has investigado.",
|
||||||
|
"start_end_equal": "# %s fue proporcionado dos veces\n\nAsegúrate de que `tanque-inicial` y `tanque-objetivo` son diferentes.",
|
||||||
|
"tanks_not_on_line": "# %s y %s no están en la misma línea\n\nAsegúrate de que `tanque-inicial` y `tanque-objetivo` están en la misma línea del árbol tecnológico.",
|
||||||
|
"unordered": "# %s de nivel superior a %s\n\nAsegúrate de proporcionar %s como el `tanque-inicial` en su lugar ya que es el tanque de nivel inferior."
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"$": "sobre",
|
"$": "sobre",
|
||||||
"description": "Toda la información que necesitas sobre el bot",
|
"description": "Toda la información que necesitas sobre el bot",
|
||||||
@@ -278,13 +310,13 @@
|
|||||||
"lethality": {
|
"lethality": {
|
||||||
"$": "Letalidad",
|
"$": "Letalidad",
|
||||||
"average_damage": "Daño promedio",
|
"average_damage": "Daño promedio",
|
||||||
"damage_per_tier": "Daño por tier",
|
"damage_per_tier": "Daño por nivel",
|
||||||
"damage_ratio": "Relación de daño",
|
"damage_ratio": "Relación de daño",
|
||||||
"average_kills": "Promedio de bajas"
|
"average_kills": "Promedio de bajas"
|
||||||
},
|
},
|
||||||
"miscellaneous": {
|
"miscellaneous": {
|
||||||
"$": "Misceláneo",
|
"$": "Misceláneo",
|
||||||
"average_tier": "Tier promedio",
|
"average_tier": "Nivel promedio",
|
||||||
"average_spots": "Promedio de detecciones",
|
"average_spots": "Promedio de detecciones",
|
||||||
"average_xp": "Promedio de XP",
|
"average_xp": "Promedio de XP",
|
||||||
"kills_to_death_ratio": "Relación bajas-muertes"
|
"kills_to_death_ratio": "Relación bajas-muertes"
|
||||||
@@ -371,7 +403,7 @@
|
|||||||
"no_ongoing_season": "# No hay temporada en curso\n\nActualmente no hay ninguna temporada de clasificación.",
|
"no_ongoing_season": "# No hay temporada en curso\n\nActualmente no hay ninguna temporada de clasificación.",
|
||||||
"deleted_player": "%s eliminado",
|
"deleted_player": "%s eliminado",
|
||||||
"neighbors": "Vecinos de clasificación",
|
"neighbors": "Vecinos de clasificación",
|
||||||
"more": "+ %s más"
|
"more": "+%s más"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"today": {
|
"today": {
|
||||||
@@ -386,7 +418,7 @@
|
|||||||
"winrate": "Tasa de victorias",
|
"winrate": "Tasa de victorias",
|
||||||
"damage": "Daño",
|
"damage": "Daño",
|
||||||
"damage_ratio": "Relación de daño",
|
"damage_ratio": "Relación de daño",
|
||||||
"tier": "Tier",
|
"tier": "Nivel",
|
||||||
"survival": "Supervivencia",
|
"survival": "Supervivencia",
|
||||||
"accuracy": "Precisión",
|
"accuracy": "Precisión",
|
||||||
"kill_ratio": "Relación de bajas"
|
"kill_ratio": "Relación de bajas"
|
||||||
@@ -394,9 +426,9 @@
|
|||||||
},
|
},
|
||||||
"owned_tanks": {
|
"owned_tanks": {
|
||||||
"$": "tanques-propios",
|
"$": "tanques-propios",
|
||||||
"description": "Muestra todos los tanques propios en un tier",
|
"description": "Muestra todos los tanques propios en un nivel",
|
||||||
"body": {
|
"body": {
|
||||||
"subtitle": "Tanques de tier %s"
|
"title": "# Tanques de %s de nivel %s\n\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": {
|
"permissions": {
|
||||||
@@ -404,9 +436,10 @@
|
|||||||
"description": "Comprueba si el bot tiene los permisos requeridos para funcionar",
|
"description": "Comprueba si el bot tiene los permisos requeridos para funcionar",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# Permisos\n\n%s",
|
"title": "# Permisos\n\n%s",
|
||||||
"view_channels": "Ver canales: necesario para que funcione el botón de actualizar",
|
"view_channels": "Ver canales: necesario para encontrar el mensaje en el cual el botón \"actualizar\" fue usado",
|
||||||
"read_message_history": "Leer el historial de mensajes: necesario para que el botón de actualizar pueda encontrar el mensaje a actualizar",
|
"read_message_history": "Leer historial de mensajes: necesario para encontrar el mensaje a actualizar",
|
||||||
"attach_files": "Adjuntar archivos: necesario para que funcionen los comandos basados en imágenes"
|
"attach_files": "Adjuntar archivos: necesario para añadir imágenes a los comandos basados en estas",
|
||||||
|
"external_emojis": "Emoticonos externos: necesario para añadir emoticonos de banderas nacionales y clases de tanque"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
|
|||||||
+38
-5
@@ -170,10 +170,42 @@
|
|||||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
||||||
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
||||||
"get_help": "Help Discord server",
|
"get_help": "Help Discord server",
|
||||||
"uncaught_error": "# Blitzkrieg ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help."
|
"uncaught_error": "# Blitzkrieg ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help.",
|
||||||
|
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"research": {
|
||||||
|
"$": "research",
|
||||||
|
"description": "Lists the expenses in researching a line",
|
||||||
|
"options": {
|
||||||
|
"target_tank": {
|
||||||
|
"$": "target-tank",
|
||||||
|
"description": "The final tank to research in the line"
|
||||||
|
},
|
||||||
|
"starting_tank": {
|
||||||
|
"$": "starting-tank",
|
||||||
|
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"subtitle": "Research",
|
||||||
|
"total": "Total",
|
||||||
|
"research": "Research: %s",
|
||||||
|
"upgrades": "Upgrades: %s",
|
||||||
|
"purchase": "Purchase: %s",
|
||||||
|
"equipment": "Equipment: %s",
|
||||||
|
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"non_tech_tree": "# %s is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||||
|
"tier_1": "# %s is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||||
|
"already_researched": "# %s is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||||
|
"start_end_equal": "# %s was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||||
|
"tanks_not_on_line": "# %s and %s are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||||
|
"unordered": "# %s higher tiered to %s\n\nMake sure to provide %s as the `starting-tank` instead as it is the lower tiered tank."
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"$": "about",
|
"$": "about",
|
||||||
"description": "All the info you need about the bot",
|
"description": "All the info you need about the bot",
|
||||||
@@ -396,7 +428,7 @@
|
|||||||
"$": "owned-tanks",
|
"$": "owned-tanks",
|
||||||
"description": "Shows all own tanks in a tier",
|
"description": "Shows all own tanks in a tier",
|
||||||
"body": {
|
"body": {
|
||||||
"subtitle": "Tier %s tanks"
|
"title": "# %s's owned tier %s tanks\n\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": {
|
"permissions": {
|
||||||
@@ -404,9 +436,10 @@
|
|||||||
"description": "Checks wether the bot has the required permissions to function",
|
"description": "Checks wether the bot has the required permissions to function",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# Permissions\n\n%s",
|
"title": "# Permissions\n\n%s",
|
||||||
"view_channels": "View channels: needed for the refresh button to work",
|
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||||
"read_message_history": "Read message history: needed for the refresh button to find the message to refresh",
|
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||||
"attach_files": "Attach files: needed for image-based commands to work"
|
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||||
|
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ping": {
|
"ping": {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export interface TankopediaPersistent {
|
|||||||
showGrid: boolean;
|
showGrid: boolean;
|
||||||
greenPenetration: boolean;
|
greenPenetration: boolean;
|
||||||
showEnvironment: boolean;
|
showEnvironment: boolean;
|
||||||
|
showSpacedArmor: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
sort: {
|
sort: {
|
||||||
@@ -123,6 +124,7 @@ export const useTankopediaPersistent = create<TankopediaPersistent>()(
|
|||||||
subscribeWithSelector<TankopediaPersistent>(() => ({
|
subscribeWithSelector<TankopediaPersistent>(() => ({
|
||||||
model: {
|
model: {
|
||||||
visual: {
|
visual: {
|
||||||
|
showSpacedArmor: true,
|
||||||
wireframe: false,
|
wireframe: false,
|
||||||
opaque: false,
|
opaque: false,
|
||||||
environment: ENVIRONMENTS[0],
|
environment: ENVIRONMENTS[0],
|
||||||
|
|||||||
@@ -2361,13 +2361,6 @@
|
|||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
|
|
||||||
"@vercel/analytics@^1.2.2":
|
|
||||||
version "1.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@vercel/analytics/-/analytics-1.2.2.tgz#715d8f203a170c06ba36b363e03b048c03060d5d"
|
|
||||||
integrity sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==
|
|
||||||
dependencies:
|
|
||||||
server-only "^0.0.1"
|
|
||||||
|
|
||||||
"@vitejs/plugin-vue@^5.0.4":
|
"@vitejs/plugin-vue@^5.0.4":
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37"
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz#508d6a0f2440f86945835d903fcc0d95d1bb8a37"
|
||||||
@@ -5049,11 +5042,6 @@ [email protected]:
|
|||||||
parseurl "~1.3.3"
|
parseurl "~1.3.3"
|
||||||
send "0.18.0"
|
send "0.18.0"
|
||||||
|
|
||||||
server-only@^0.0.1:
|
|
||||||
version "0.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/server-only/-/server-only-0.0.1.tgz#0f366bb6afb618c37c9255a314535dc412cd1c9e"
|
|
||||||
integrity sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==
|
|
||||||
|
|
||||||
set-function-length@^1.2.1:
|
set-function-length@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425"
|
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.1.tgz#47cc5945f2c771e2cf261c6737cf9684a2a5e425"
|
||||||
|
|||||||
Reference in new issue
Block a user