From 2f7f2362bbe46d2fe34a3a13d33c2fff4126b20a Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:58:16 -0600 Subject: [PATCH 1/3] feat: auction command --- packages/bot/src/commands/auction.ts | 126 ++++++++++++++++++ .../bot/src/events/interactionCreate/index.ts | 2 + packages/bot/src/main.ts | 4 + packages/bot/src/workers/bot.ts | 4 + packages/bot/src/workers/render.ts | 2 + packages/core/lang/en-US.json | 21 +++ packages/core/src/blitz/classes.ts | 5 + packages/core/src/blitz/index.ts | 1 + .../scripts/src/buildAssets/definitions.ts | 2 +- 9 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 packages/bot/src/commands/auction.ts create mode 100644 packages/core/src/blitz/classes.ts diff --git a/packages/bot/src/commands/auction.ts b/packages/bot/src/commands/auction.ts new file mode 100644 index 000000000..eac778a38 --- /dev/null +++ b/packages/bot/src/commands/auction.ts @@ -0,0 +1,126 @@ +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 | null; + next_price_timestamp?: number | null; + } + | { + 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((resolve) => { + resolve({ + command: createLocalizedCommand('auction', [ + { subcommand: 'available' }, + { subcommand: 'setup' }, + ]), + + async handler(interaction) { + 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); + const seeableTanks = data.results.filter((result) => result.available); + const { t, translate } = translator(interaction.locale); + + const title = `# ${t`bot.commands.auction.subcommands.available.body.title`}`; + const subtitle = `-# ${translate( + 'bot.commands.auction.subcommands.available.body.available', + [`${seeableTanks.length} / ${data.results.length}`], + )}`; + const body = seeableTanks + .map((data, index) => { + const tank = awaitedTankDefinitions.tanks[data.entity!.id]; + + if (!tank) return ''; + + const name = `[${tank.name}]()`; + const next = translate( + 'bot.commands.auction.subcommands.available.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'); + + return `${title}\n${subtitle}\n\n${body}`; + }, + }); +}); diff --git a/packages/bot/src/events/interactionCreate/index.ts b/packages/bot/src/events/interactionCreate/index.ts index 0af7d04be..5d244c8ed 100644 --- a/packages/bot/src/events/interactionCreate/index.ts +++ b/packages/bot/src/events/interactionCreate/index.ts @@ -15,6 +15,7 @@ import { SlashCommandSubcommandsOnlyBuilder, } from 'discord.js'; import { aboutCommand } from '../../commands/about'; +import { auctionCommand } from '../../commands/auction'; import { breakdownCommand } from '../../commands/breakdown'; import { debugCommand } from '../../commands/debug'; import { evolutionCommand } from '../../commands/evolution'; @@ -76,6 +77,7 @@ interface CommandRegistryExplicit extends CommandRegistryBase { export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit; export const COMMANDS_RAW: Promise[] = [ + auctionCommand, permissionsCommand, debugCommand, aboutCommand, diff --git a/packages/bot/src/main.ts b/packages/bot/src/main.ts index 5a2aeb60d..dcfb6a738 100644 --- a/packages/bot/src/main.ts +++ b/packages/bot/src/main.ts @@ -1,8 +1,12 @@ import { manager } from './core/discord/manager'; +console.log('pre manager event listeners and spawn'); + manager .on('shardCreate', (shard) => { console.log(`🟡 Launching shard ${shard.id}`); shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`)); }) .spawn(); + +console.log('post manager event listeners and spawn'); diff --git a/packages/bot/src/workers/bot.ts b/packages/bot/src/workers/bot.ts index 4d19375ef..65f3a4dee 100644 --- a/packages/bot/src/workers/bot.ts +++ b/packages/bot/src/workers/bot.ts @@ -6,4 +6,8 @@ console.log(`🟡 Launching bot ${client.shard?.ids[0]}`); registerProcesses(); +console.log(`post register processes on shard ${client.shard?.ids[0]}`); + client.login(assertSecret(import.meta.env.DISCORD_TOKEN)); + +console.log(`post client login on shard ${client.shard?.ids[0]}`); diff --git a/packages/bot/src/workers/render.ts b/packages/bot/src/workers/render.ts index 0950d7028..1838e44ad 100644 --- a/packages/bot/src/workers/render.ts +++ b/packages/bot/src/workers/render.ts @@ -7,3 +7,5 @@ parentPort?.on('message', async (svg: string) => { const png = svgToPng(svg); parentPort?.postMessage(png); }); + +console.log(`post render thread parent port on thread ${threadId}`); diff --git a/packages/core/lang/en-US.json b/packages/core/lang/en-US.json index 4a0551de5..d23c62126 100644 --- a/packages/core/lang/en-US.json +++ b/packages/core/lang/en-US.json @@ -291,6 +291,27 @@ }, "commands": { + "auction": { + "$": "auction", + "description": "Tanks available in the auction", + + "subcommands": { + "available": { + "$": "available", + "description": "Tanks available right now in the auction", + "body": { + "title": "Blitz Auction", + "available": "%s available", + "next": "Next price: %s" + } + }, + "setup": { + "$": "setup", + "description": "Set up a channel to receive auction updates" + } + } + }, + "replay": { "$": "replay", "description": "Display replay results" diff --git a/packages/core/src/blitz/classes.ts b/packages/core/src/blitz/classes.ts new file mode 100644 index 000000000..61a6bd4a6 --- /dev/null +++ b/packages/core/src/blitz/classes.ts @@ -0,0 +1,5 @@ +export type BlitzTankClass = + | 'lightTank' + | 'mediumTank' + | 'heavyTank' + | 'AT-SPG'; diff --git a/packages/core/src/blitz/index.ts b/packages/core/src/blitz/index.ts index aa2aadf58..5304654f2 100644 --- a/packages/core/src/blitz/index.ts +++ b/packages/core/src/blitz/index.ts @@ -1,5 +1,6 @@ export * from './canSplash'; export * from './clans'; +export * from './classes'; export * from './constants'; export * from './equipmentPrice'; export * from './fetchBlitz'; diff --git a/packages/scripts/src/buildAssets/definitions.ts b/packages/scripts/src/buildAssets/definitions.ts index 070aef7b8..d356268bf 100644 --- a/packages/scripts/src/buildAssets/definitions.ts +++ b/packages/scripts/src/buildAssets/definitions.ts @@ -1,6 +1,7 @@ import { Armor, assertSecret, + BlitzTankClass, CamouflageDefinitions, Consumable, ConsumableDefinitions, @@ -70,7 +71,6 @@ const blitzTankFilterDefinitionCategoryToBlitzkit: Record< function vector3TupleToBlitzkit(tuple: Vector3Tuple) { return { x: tuple[0], y: tuple[1], z: tuple[2] } satisfies Vector3; } -type BlitzTankClass = 'lightTank' | 'mediumTank' | 'heavyTank' | 'AT-SPG'; const blitzTankClassToBlitzkit: Record = { lightTank: TankClass.LIGHT, 'AT-SPG': TankClass.TANK_DESTROYER, From df34226a220de7f53f838fe94e36257f7d174bd1 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:11:43 -0600 Subject: [PATCH 2/3] feat: more features --- bun.lockb | Bin 389213 -> 389594 bytes packages/bot/package.json | 2 +- packages/bot/src/commands/auction.ts | 48 ++++++++++++++------------- packages/core/lang/en-US.json | 26 ++++++--------- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/bun.lockb b/bun.lockb index 388393570d525ea4ef8910921e4f24849a0a10dd..400436ef2434116ce6fe99620241d447e3bf9b93 100644 GIT binary patch delta 4072 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 UyGF{f#_o&ePR(fUFk5_o1)4HTUjP6A diff --git a/packages/bot/package.json b/packages/bot/package.json index f66ab8fd3..6e5c7e2fe 100644 --- a/packages/bot/package.json +++ b/packages/bot/package.json @@ -7,7 +7,7 @@ "@blitzkit/core": "workspace:*", "satori": "^0.10.14", "@resvg/resvg-js": "^2.6.2", - "discord.js": "^14.15.3", + "discord.js": "^14.16.3", "react": "^18.3.1", "@radix-ui/colors": "^3.0.0", "fuzzysort": "^2.0.4", diff --git a/packages/bot/src/commands/auction.ts b/packages/bot/src/commands/auction.ts index eac778a38..fa886a125 100644 --- a/packages/bot/src/commands/auction.ts +++ b/packages/bot/src/commands/auction.ts @@ -29,8 +29,8 @@ type Result = next_price?: Price | null; available: true; display?: boolean; - next_price_datetime?: Date | null; - next_price_timestamp?: number | null; + next_price_datetime: Date; + next_price_timestamp: number; } | { available: false; @@ -69,12 +69,10 @@ interface Currency { export const auctionCommand = new Promise((resolve) => { resolve({ - command: createLocalizedCommand('auction', [ - { subcommand: 'available' }, - { subcommand: 'setup' }, - ]), + command: createLocalizedCommand('auction'), async handler(interaction) { + const { t, translate } = translator(interaction.locale); const awaitedTankDefinitions = await tankDefinitions; const region: Region = 'com'; const pageSize = 80; @@ -86,15 +84,21 @@ export const auctionCommand = new Promise((resolve) => { pageSize }&type[]=vehicle&saleable=${saleable}`, ).then((response) => response.json() as Promise); - const seeableTanks = data.results.filter((result) => result.available); - const { t, translate } = translator(interaction.locale); + const saleableTanks = data.results.filter((result) => result.available); - const title = `# ${t`bot.commands.auction.subcommands.available.body.title`}`; - const subtitle = `-# ${translate( - 'bot.commands.auction.subcommands.available.body.available', - [`${seeableTanks.length} / ${data.results.length}`], - )}`; - const body = seeableTanks + 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}`, + ``, + '', + ])}`; + const body = saleableTanks .map((data, index) => { const tank = awaitedTankDefinitions.tanks[data.entity!.id]; @@ -103,14 +107,11 @@ export const auctionCommand = new Promise((resolve) => { const name = `[${tank.name}]()`; - const next = translate( - 'bot.commands.auction.subcommands.available.body.next', - [ - `<:gold:1317173197082333244> ${data.next_price!.value.toLocaleString( - interaction.locale, - )}`, - ], - ); + const next = translate('bot.commands.auction.body.next', [ + `<:gold:1317173197082333244> ${data.next_price!.value.toLocaleString( + interaction.locale, + )}`, + ]); return `${ index + 1 @@ -119,8 +120,9 @@ export const auctionCommand = new Promise((resolve) => { )}\n-# ${next}`; }) .join('\n\n'); + const content = `${title}\n${subtitle}\n\n${body}`; - return `${title}\n${subtitle}\n\n${body}`; + return content; }, }); }); diff --git a/packages/core/lang/en-US.json b/packages/core/lang/en-US.json index d23c62126..3ebb10239 100644 --- a/packages/core/lang/en-US.json +++ b/packages/core/lang/en-US.json @@ -293,22 +293,18 @@ "commands": { "auction": { "$": "auction", - "description": "Tanks available in the auction", + "description": "Tanks available right now in the auction", - "subcommands": { - "available": { - "$": "available", - "description": "Tanks available right now in the auction", - "body": { - "title": "Blitz Auction", - "available": "%s available", - "next": "Next price: %s" - } - }, - "setup": { - "$": "setup", - "description": "Set up a channel to receive auction updates" - } + "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" } }, From 4e513998a9de307e5bc91d42ede0bfda10d7e128 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 13 Dec 2024 16:14:16 -0600 Subject: [PATCH 3/3] feat: logs --- docs/changelogs/1.26.1.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 docs/changelogs/1.26.1.md diff --git a/docs/changelogs/1.26.1.md b/docs/changelogs/1.26.1.md new file mode 100644 index 000000000..1a0554bc5 --- /dev/null +++ b/docs/changelogs/1.26.1.md @@ -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! diff --git a/package.json b/package.json index b52ca9d99..245a2a4d4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "blitzkit", "private": true, - "version": "1.26.0", + "version": "1.26.1", "description": "🎉 Tools for everything World of Tanks Blitz", "type": "module", "types": "./types.d.ts",