mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +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));
|
writeFile('test.json', JSON.stringify(tankDefinitions, null, 2));
|
||||||
|
|
||||||
return;
|
|
||||||
await commitAssets(
|
await commitAssets(
|
||||||
'definitions',
|
'definitions',
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -32,10 +32,9 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { translate } = translator(interaction.locale);
|
const { translate } = translator(interaction.locale);
|
||||||
const tier = Number(interaction.options.getString('tier'));
|
const tier = Number(interaction.options.getString('tier'));
|
||||||
const account = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
const { id, region: server } = account;
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const accountInfo = await getAccountInfo(server, id);
|
const tankStats = await getTankStats(region, id, interaction.locale);
|
||||||
const tankStats = await getTankStats(server, id, interaction.locale);
|
|
||||||
const filteredTanks = (
|
const filteredTanks = (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
tankStats.map(async (tankData) => ({
|
tankStats.map(async (tankData) => ({
|
||||||
@@ -44,7 +43,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
).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 groupedTanks: Record<string, TankDefinition[]> = {};
|
||||||
const nations: string[] = [];
|
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 { deburr } from 'lodash';
|
||||||
import { Vector2Tuple } from 'three';
|
import { Vector2Tuple } from 'three';
|
||||||
import { TankClass, TreeType } from '../../../components/Tanks';
|
import { TankClass, TreeType } from '../../../components/Tanks';
|
||||||
import { asset } from '../asset';
|
import { superDecompress } from '../superDecompress';
|
||||||
import { fetchCdonLz4 } from '../fetchCdonLz4';
|
|
||||||
import { TIERS } from './constants';
|
import { TIERS } from './constants';
|
||||||
|
|
||||||
export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
|
export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
|
||||||
@@ -137,8 +137,12 @@ export type ShellDefinition = {
|
|||||||
explosionRadius?: number;
|
explosionRadius?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
// export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
|
||||||
asset('definitions/tanks.cdon.lz4'),
|
// 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) => {
|
const entries = new Promise<TankDefinition[]>(async (resolve) => {
|
||||||
@@ -158,6 +162,7 @@ export const tankNames = tanksDefinitionsArray.then((tanks) =>
|
|||||||
id,
|
id,
|
||||||
original: tank.name,
|
original: tank.name,
|
||||||
combined: `${tank.name}${deburr(tank.name)}${tank.nameFull ? `${tank.nameFull}${deburr(tank.nameFull)}` : ''}`,
|
combined: `${tank.name}${deburr(tank.name)}${tank.nameFull ? `${tank.nameFull}${deburr(tank.nameFull)}` : ''}`,
|
||||||
|
treeType: tank.treeType,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ import {
|
|||||||
OVERFLOW_SUFFIX,
|
OVERFLOW_SUFFIX,
|
||||||
} from './autocompleteClan/constants';
|
} from './autocompleteClan/constants';
|
||||||
|
|
||||||
|
const tankNamesTechTreeOnly = tankNames.then((names) =>
|
||||||
|
names.filter((tank) => tank.treeType === 'researchable'),
|
||||||
|
);
|
||||||
|
|
||||||
export default async function autocompleteTanks(
|
export default async function autocompleteTanks(
|
||||||
interaction: AutocompleteInteraction<CacheType>,
|
interaction: AutocompleteInteraction<CacheType>,
|
||||||
|
techTreeOnly = false,
|
||||||
) {
|
) {
|
||||||
const focusedOption = interaction.options.getFocused(true);
|
const focusedOption = interaction.options.getFocused(true);
|
||||||
if (focusedOption.name !== 'tank') return;
|
if (focusedOption.name !== 'tank') return;
|
||||||
@@ -19,10 +24,14 @@ export default async function autocompleteTanks(
|
|||||||
await interaction.respond(
|
await interaction.respond(
|
||||||
focusedOption.value
|
focusedOption.value
|
||||||
? await Promise.all(
|
? await Promise.all(
|
||||||
go(focusedOption.value, await tankNames, {
|
go(
|
||||||
keys: ['combined'],
|
focusedOption.value,
|
||||||
limit: 10,
|
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||||
}).map(async (item) => {
|
{
|
||||||
|
keys: ['combined'],
|
||||||
|
limit: 10,
|
||||||
|
},
|
||||||
|
).map(async (item) => {
|
||||||
let name = item.obj.original;
|
let name = item.obj.original;
|
||||||
|
|
||||||
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { permissionsCommand } from '../../commands/permissions';
|
|||||||
import { pingCommand } from '../../commands/ping';
|
import { pingCommand } from '../../commands/ping';
|
||||||
import { playerInfoCommand } from '../../commands/playerInfo';
|
import { playerInfoCommand } from '../../commands/playerInfo';
|
||||||
import { ratingsCommand } from '../../commands/ratings';
|
import { ratingsCommand } from '../../commands/ratings';
|
||||||
|
import { researchCommand } from '../../commands/research';
|
||||||
import { searchClansCommand } from '../../commands/searchClans';
|
import { searchClansCommand } from '../../commands/searchClans';
|
||||||
import { searchPlayersCommand } from '../../commands/searchPlayers';
|
import { searchPlayersCommand } from '../../commands/searchPlayers';
|
||||||
import { statsCommand } from '../../commands/stats';
|
import { statsCommand } from '../../commands/stats';
|
||||||
@@ -92,6 +93,7 @@ export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
|||||||
statsCommand,
|
statsCommand,
|
||||||
ratingsCommand,
|
ratingsCommand,
|
||||||
todayCommand,
|
todayCommand,
|
||||||
|
researchCommand,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => {
|
export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => {
|
||||||
|
|||||||
@@ -195,6 +195,11 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"research": {
|
||||||
|
"$": "research",
|
||||||
|
"description": "Lists the expenses in researching a line"
|
||||||
|
},
|
||||||
|
|
||||||
"about": {
|
"about": {
|
||||||
"$": "about",
|
"$": "about",
|
||||||
"description": "All the info you need about the bot",
|
"description": "All the info you need about the bot",
|
||||||
|
|||||||
Reference in new issue
Block a user