mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-22 11:17:05 +02:00
feat: resolving lines
This commit is contained in:
1 parent
5372068830
commit
43e1d53d39
9 files changed
+149
-14
No files matched your search
@@ -1022,7 +1022,6 @@ export async function definitions(production: boolean) {
|
||||
|
||||
writeFile('test.json', JSON.stringify(tankDefinitions, null, 2));
|
||||
|
||||
return;
|
||||
await commitAssets(
|
||||
'definitions',
|
||||
[
|
||||
|
||||
@@ -32,10 +32,9 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
async handler(interaction) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const tier = Number(interaction.options.getString('tier'));
|
||||
const account = await resolvePlayerFromCommand(interaction);
|
||||
const { id, region: server } = account;
|
||||
const accountInfo = await getAccountInfo(server, id);
|
||||
const tankStats = await getTankStats(server, id, interaction.locale);
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const tankStats = await getTankStats(region, id, interaction.locale);
|
||||
const filteredTanks = (
|
||||
await Promise.all(
|
||||
tankStats.map(async (tankData) => ({
|
||||
@@ -44,7 +43,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
})),
|
||||
)
|
||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
||||
const clanAccountInfo = await getClanAccountInfo(server, id, ['clan']);
|
||||
const clanAccountInfo = await getClanAccountInfo(region, id, ['clan']);
|
||||
const groupedTanks: Record<string, TankDefinition[]> = {};
|
||||
const nations: string[] = [];
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { escapeMarkdown } from 'discord.js';
|
||||
import CommandWrapper from '../components/CommandWrapper';
|
||||
import TitleBar from '../components/TitleBar';
|
||||
import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
||||
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
||||
import getTankStats from '../core/blitz/getTankStats';
|
||||
import resolveTankId from '../core/blitz/resolveTankId';
|
||||
import { buildTechTreeLine } from '../core/blitzkrieg/buildTechTreeLine';
|
||||
import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL';
|
||||
import { resolveAncestry } from '../core/blitzkrieg/resolveAncestry';
|
||||
import { tankDefinitions } from '../core/blitzkrieg/tankDefinitions';
|
||||
import addTankChoices from '../core/discord/addTankChoices';
|
||||
import autocompleteTanks from '../core/discord/autocompleteTanks';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
resolve({
|
||||
inProduction: true,
|
||||
inPublic: true,
|
||||
|
||||
command: createLocalizedCommand('research').addStringOption(addTankChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tankId = await resolveTankId(
|
||||
interaction.options.getString('tank', true),
|
||||
interaction.locale,
|
||||
);
|
||||
const tank = awaitedTankDefinitions[tankId];
|
||||
|
||||
if (tank.treeType !== 'researchable') {
|
||||
return `# ${escapeMarkdown(tank.name)} is not researchable\n\nThis tank is not on the tech tree.`;
|
||||
}
|
||||
|
||||
if (tank.tier === 1) {
|
||||
return `# ${escapeMarkdown(tank.name)} is not researchable\n\nThis tank is a tier I and is always unlocked.`;
|
||||
}
|
||||
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const tankStats = await getTankStats(region, id, interaction.locale);
|
||||
const ancestry = await resolveAncestry(tankId);
|
||||
const firstOwnedTechTree = ancestry.find((id) =>
|
||||
tankStats.some(({ tank_id }) => tank_id === id),
|
||||
);
|
||||
|
||||
if (firstOwnedTechTree === undefined) {
|
||||
return `idk what to call this error lol`;
|
||||
}
|
||||
|
||||
const line = await buildTechTreeLine(firstOwnedTechTree, tankId);
|
||||
const { nickname } = await getAccountInfo(region, id);
|
||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
||||
const clanImage = clan ? emblemIdToURL(clan.emblem_set_id) : undefined;
|
||||
|
||||
return (
|
||||
<CommandWrapper>
|
||||
<TitleBar
|
||||
title={nickname}
|
||||
image={clanImage}
|
||||
description={`Research • ${tank.name}`}
|
||||
/>
|
||||
</CommandWrapper>
|
||||
);
|
||||
},
|
||||
|
||||
autocomplete(interaction) {
|
||||
autocompleteTanks(interaction, true);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { resolveAncestry } from './resolveAncestry';
|
||||
import { tankDefinitions } from './tankDefinitions';
|
||||
|
||||
export async function buildTechTreeLine(start: number, end: number) {
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const endTank = awaitedTankDefinitions[end];
|
||||
if (!endTank.ancestors) throw new Error('End tank has no ancestors');
|
||||
const line = [end];
|
||||
|
||||
if (start === end) return line;
|
||||
for (const ancestorId of endTank.ancestors) {
|
||||
if ((await resolveAncestry(ancestorId)).includes(start)) {
|
||||
line.push(...(await buildTechTreeLine(start, ancestorId)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { tankDefinitions } from './tankDefinitions';
|
||||
|
||||
export async function resolveAncestry(id: number) {
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tank = awaitedTankDefinitions[id];
|
||||
const ancestors: number[] = [];
|
||||
|
||||
if (tank.ancestors) {
|
||||
for (const ancestor of tank.ancestors) {
|
||||
if (!ancestors.includes(ancestor)) {
|
||||
ancestors.push(ancestor);
|
||||
|
||||
for (const ancestorLayer2 of await resolveAncestry(ancestor)) {
|
||||
if (!ancestors.includes(ancestorLayer2)) {
|
||||
ancestors.push(ancestorLayer2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ancestors.sort(
|
||||
(a, b) => awaitedTankDefinitions[b].tier - awaitedTankDefinitions[a].tier,
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { readFile } from 'fs/promises';
|
||||
import { deburr } from 'lodash';
|
||||
import { Vector2Tuple } from 'three';
|
||||
import { TankClass, TreeType } from '../../../components/Tanks';
|
||||
import { asset } from '../asset';
|
||||
import { fetchCdonLz4 } from '../fetchCdonLz4';
|
||||
import { superDecompress } from '../superDecompress';
|
||||
import { TIERS } from './constants';
|
||||
|
||||
export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
|
||||
@@ -137,8 +137,12 @@ export type ShellDefinition = {
|
||||
explosionRadius?: number;
|
||||
};
|
||||
|
||||
export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
||||
asset('definitions/tanks.cdon.lz4'),
|
||||
// export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
||||
// asset('definitions/tanks.cdon.lz4'),
|
||||
// );
|
||||
|
||||
export const tankDefinitions = readFile('test.tanks.cdon.lz4').then((data) =>
|
||||
superDecompress<TankDefinitions>(data.buffer),
|
||||
);
|
||||
|
||||
const entries = new Promise<TankDefinition[]>(async (resolve) => {
|
||||
@@ -158,6 +162,7 @@ export const tankNames = tanksDefinitionsArray.then((tanks) =>
|
||||
id,
|
||||
original: tank.name,
|
||||
combined: `${tank.name}${deburr(tank.name)}${tank.nameFull ? `${tank.nameFull}${deburr(tank.nameFull)}` : ''}`,
|
||||
treeType: tank.treeType,
|
||||
};
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -10,8 +10,13 @@ import {
|
||||
OVERFLOW_SUFFIX,
|
||||
} from './autocompleteClan/constants';
|
||||
|
||||
const tankNamesTechTreeOnly = tankNames.then((names) =>
|
||||
names.filter((tank) => tank.treeType === 'researchable'),
|
||||
);
|
||||
|
||||
export default async function autocompleteTanks(
|
||||
interaction: AutocompleteInteraction<CacheType>,
|
||||
techTreeOnly = false,
|
||||
) {
|
||||
const focusedOption = interaction.options.getFocused(true);
|
||||
if (focusedOption.name !== 'tank') return;
|
||||
@@ -19,10 +24,14 @@ export default async function autocompleteTanks(
|
||||
await interaction.respond(
|
||||
focusedOption.value
|
||||
? await Promise.all(
|
||||
go(focusedOption.value, await tankNames, {
|
||||
keys: ['combined'],
|
||||
limit: 10,
|
||||
}).map(async (item) => {
|
||||
go(
|
||||
focusedOption.value,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: ['combined'],
|
||||
limit: 10,
|
||||
},
|
||||
).map(async (item) => {
|
||||
let name = item.obj.original;
|
||||
|
||||
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { permissionsCommand } from '../../commands/permissions';
|
||||
import { pingCommand } from '../../commands/ping';
|
||||
import { playerInfoCommand } from '../../commands/playerInfo';
|
||||
import { ratingsCommand } from '../../commands/ratings';
|
||||
import { researchCommand } from '../../commands/research';
|
||||
import { searchClansCommand } from '../../commands/searchClans';
|
||||
import { searchPlayersCommand } from '../../commands/searchPlayers';
|
||||
import { statsCommand } from '../../commands/stats';
|
||||
@@ -92,6 +93,7 @@ export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
||||
statsCommand,
|
||||
ratingsCommand,
|
||||
todayCommand,
|
||||
researchCommand,
|
||||
];
|
||||
|
||||
export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => {
|
||||
|
||||
@@ -195,6 +195,11 @@
|
||||
},
|
||||
|
||||
"commands": {
|
||||
"research": {
|
||||
"$": "research",
|
||||
"description": "Lists the expenses in researching a line"
|
||||
},
|
||||
|
||||
"about": {
|
||||
"$": "about",
|
||||
"description": "All the info you need about the bot",
|
||||
|
||||
Reference in new issue
Block a user