mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
Merge branch 'main' into dev
This commit is contained in:
commit
ab798b722f
12 files changed
+175
-3
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
# BlitzKit 1.26.1
|
||||||
|
|
||||||
|
The auctions are here!
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added the `/auction` command
|
||||||
|
- No need to login or go to the official website, just use `/auction`
|
||||||
|
- Everything built into Discord, one step at a time!
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.26.0",
|
"version": "1.26.1",
|
||||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./types.d.ts",
|
"types": "./types.d.ts",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"@blitzkit/core": "workspace:*",
|
"@blitzkit/core": "workspace:*",
|
||||||
"satori": "^0.10.14",
|
"satori": "^0.10.14",
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"discord.js": "^14.15.3",
|
"discord.js": "^14.16.3",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"fuzzysort": "^2.0.4",
|
"fuzzysort": "^2.0.4",
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import {
|
||||||
|
BlitzTankClass,
|
||||||
|
Region,
|
||||||
|
regionToRegionSubdomain,
|
||||||
|
} from '@blitzkit/core';
|
||||||
|
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
||||||
|
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||||
|
import { translator } from '../core/localization/translator';
|
||||||
|
import { CommandRegistry } from '../events/interactionCreate';
|
||||||
|
|
||||||
|
interface Auction {
|
||||||
|
count: number;
|
||||||
|
has_next: boolean;
|
||||||
|
results: Result[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result =
|
||||||
|
| {
|
||||||
|
id?: number;
|
||||||
|
type: 'vehicle';
|
||||||
|
countable?: boolean;
|
||||||
|
entity?: Entity;
|
||||||
|
initial_count?: number;
|
||||||
|
current_count?: number;
|
||||||
|
saleable?: boolean;
|
||||||
|
available_from?: Date;
|
||||||
|
available_before?: Date;
|
||||||
|
price?: Price;
|
||||||
|
next_price?: Price | null;
|
||||||
|
available: true;
|
||||||
|
display?: boolean;
|
||||||
|
next_price_datetime: Date;
|
||||||
|
next_price_timestamp: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
available: false;
|
||||||
|
type: 'vehicle';
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Entity {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
nation: string;
|
||||||
|
subnation: string;
|
||||||
|
use_subnation_flag: boolean;
|
||||||
|
type_slug: BlitzTankClass;
|
||||||
|
level: number;
|
||||||
|
roman_level: string;
|
||||||
|
user_string: string;
|
||||||
|
image_url: string;
|
||||||
|
preview_image_url: string;
|
||||||
|
is_premium: boolean;
|
||||||
|
is_collectible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Price {
|
||||||
|
currency: Currency;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Currency {
|
||||||
|
name: 'gold';
|
||||||
|
count: number;
|
||||||
|
title: 'Gold';
|
||||||
|
image_url: string;
|
||||||
|
sizes: unknown;
|
||||||
|
type: 'currency';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
|
resolve({
|
||||||
|
command: createLocalizedCommand('auction'),
|
||||||
|
|
||||||
|
async handler(interaction) {
|
||||||
|
const { t, translate } = translator(interaction.locale);
|
||||||
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
const region: Region = 'com';
|
||||||
|
const pageSize = 80;
|
||||||
|
const saleable = true;
|
||||||
|
const data = await fetch(
|
||||||
|
`https://${regionToRegionSubdomain(
|
||||||
|
region,
|
||||||
|
)}.wotblitz.com/en/api/events/items/auction/?page_size=${
|
||||||
|
pageSize
|
||||||
|
}&type[]=vehicle&saleable=${saleable}`,
|
||||||
|
).then((response) => response.json() as Promise<Auction>);
|
||||||
|
const saleableTanks = data.results.filter((result) => result.available);
|
||||||
|
|
||||||
|
if (saleableTanks.length === 0) {
|
||||||
|
return t`bot.commands.auction.errors.no_auction`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextPricesTimestamp = saleableTanks[0].next_price_timestamp;
|
||||||
|
|
||||||
|
const title = `# ${t`bot.commands.auction.body.title`}`;
|
||||||
|
const subtitle = `${translate('bot.commands.auction.body.subtitle', [
|
||||||
|
`${saleableTanks.length} / ${data.results.length}`,
|
||||||
|
`<t:${nextPricesTimestamp}:R>`,
|
||||||
|
'<https://wotblitz.com/auction/>',
|
||||||
|
])}`;
|
||||||
|
const body = saleableTanks
|
||||||
|
.map((data, index) => {
|
||||||
|
const tank = awaitedTankDefinitions.tanks[data.entity!.id];
|
||||||
|
|
||||||
|
if (!tank) return '';
|
||||||
|
|
||||||
|
const name = `[${tank.name}](<https://blitzkit.app/tools/tankopedia/${
|
||||||
|
tank.id
|
||||||
|
}>)`;
|
||||||
|
const next = translate('bot.commands.auction.body.next', [
|
||||||
|
`<:gold:1317173197082333244> ${data.next_price!.value.toLocaleString(
|
||||||
|
interaction.locale,
|
||||||
|
)}`,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return `${
|
||||||
|
index + 1
|
||||||
|
}. ${name} <:gold:1317173197082333244> ${data.price!.value.toLocaleString(
|
||||||
|
interaction.locale,
|
||||||
|
)}\n-# ${next}`;
|
||||||
|
})
|
||||||
|
.join('\n\n');
|
||||||
|
const content = `${title}\n${subtitle}\n\n${body}`;
|
||||||
|
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
SlashCommandSubcommandsOnlyBuilder,
|
SlashCommandSubcommandsOnlyBuilder,
|
||||||
} from 'discord.js';
|
} from 'discord.js';
|
||||||
import { aboutCommand } from '../../commands/about';
|
import { aboutCommand } from '../../commands/about';
|
||||||
|
import { auctionCommand } from '../../commands/auction';
|
||||||
import { breakdownCommand } from '../../commands/breakdown';
|
import { breakdownCommand } from '../../commands/breakdown';
|
||||||
import { debugCommand } from '../../commands/debug';
|
import { debugCommand } from '../../commands/debug';
|
||||||
import { evolutionCommand } from '../../commands/evolution';
|
import { evolutionCommand } from '../../commands/evolution';
|
||||||
@@ -76,6 +77,7 @@ interface CommandRegistryExplicit extends CommandRegistryBase {
|
|||||||
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
||||||
|
|
||||||
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
||||||
|
auctionCommand,
|
||||||
permissionsCommand,
|
permissionsCommand,
|
||||||
debugCommand,
|
debugCommand,
|
||||||
aboutCommand,
|
aboutCommand,
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { manager } from './core/discord/manager';
|
import { manager } from './core/discord/manager';
|
||||||
|
|
||||||
|
console.log('pre manager event listeners and spawn');
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.on('shardCreate', (shard) => {
|
.on('shardCreate', (shard) => {
|
||||||
console.log(`🟡 Launching shard ${shard.id}`);
|
console.log(`🟡 Launching shard ${shard.id}`);
|
||||||
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
|
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
|
||||||
})
|
})
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
|
console.log('post manager event listeners and spawn');
|
||||||
@@ -6,4 +6,8 @@ console.log(`🟡 Launching bot ${client.shard?.ids[0]}`);
|
|||||||
|
|
||||||
registerProcesses();
|
registerProcesses();
|
||||||
|
|
||||||
|
console.log(`post register processes on shard ${client.shard?.ids[0]}`);
|
||||||
|
|
||||||
client.login(assertSecret(import.meta.env.DISCORD_TOKEN));
|
client.login(assertSecret(import.meta.env.DISCORD_TOKEN));
|
||||||
|
|
||||||
|
console.log(`post client login on shard ${client.shard?.ids[0]}`);
|
||||||
@@ -7,3 +7,5 @@ parentPort?.on('message', async (svg: string) => {
|
|||||||
const png = svgToPng(svg);
|
const png = svgToPng(svg);
|
||||||
parentPort?.postMessage(png);
|
parentPort?.postMessage(png);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(`post render thread parent port on thread ${threadId}`);
|
||||||
@@ -291,6 +291,23 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"auction": {
|
||||||
|
"$": "auction",
|
||||||
|
"description": "Tanks available right now in the auction",
|
||||||
|
|
||||||
|
"body": {
|
||||||
|
"title": "Blitz Auction",
|
||||||
|
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||||
|
"next": "Next price: %s"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"bid": "Bid now"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"replay": {
|
"replay": {
|
||||||
"$": "replay",
|
"$": "replay",
|
||||||
"description": "Display replay results"
|
"description": "Display replay results"
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export type BlitzTankClass =
|
||||||
|
| 'lightTank'
|
||||||
|
| 'mediumTank'
|
||||||
|
| 'heavyTank'
|
||||||
|
| 'AT-SPG';
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export * from './canSplash';
|
export * from './canSplash';
|
||||||
export * from './clans';
|
export * from './clans';
|
||||||
|
export * from './classes';
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
export * from './equipmentPrice';
|
export * from './equipmentPrice';
|
||||||
export * from './fetchBlitz';
|
export * from './fetchBlitz';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Armor,
|
Armor,
|
||||||
assertSecret,
|
assertSecret,
|
||||||
|
BlitzTankClass,
|
||||||
CamouflageDefinitions,
|
CamouflageDefinitions,
|
||||||
Consumable,
|
Consumable,
|
||||||
ConsumableDefinitions,
|
ConsumableDefinitions,
|
||||||
@@ -70,7 +71,6 @@ const blitzTankFilterDefinitionCategoryToBlitzkit: Record<
|
|||||||
function vector3TupleToBlitzkit(tuple: Vector3Tuple) {
|
function vector3TupleToBlitzkit(tuple: Vector3Tuple) {
|
||||||
return { x: tuple[0], y: tuple[1], z: tuple[2] } satisfies Vector3;
|
return { x: tuple[0], y: tuple[1], z: tuple[2] } satisfies Vector3;
|
||||||
}
|
}
|
||||||
type BlitzTankClass = 'lightTank' | 'mediumTank' | 'heavyTank' | 'AT-SPG';
|
|
||||||
const blitzTankClassToBlitzkit: Record<BlitzTankClass, TankClass> = {
|
const blitzTankClassToBlitzkit: Record<BlitzTankClass, TankClass> = {
|
||||||
lightTank: TankClass.LIGHT,
|
lightTank: TankClass.LIGHT,
|
||||||
'AT-SPG': TankClass.TANK_DESTROYER,
|
'AT-SPG': TankClass.TANK_DESTROYER,
|
||||||
|
|||||||
Reference in new issue
Block a user