mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: added future features 👀
This commit is contained in:
1 parent
0db96795b3
commit
db976c4ae9
7 files changed
+214
-138
No files matched your search
+132
-7
@@ -2,20 +2,130 @@ import { SlashCommandBuilder } from 'discord.js';
|
|||||||
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
|
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
||||||
import resolveTankId from '../core/blitz/resolveTankId';
|
import resolveTankId from '../core/blitz/resolveTankId';
|
||||||
|
import getPlayerHistories from '../core/blitzstars/getPlayerHistories';
|
||||||
|
import getTankHistories from '../core/blitzstars/getTankHistories';
|
||||||
import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups';
|
import addStatTypeSubCommandGroups from '../core/discord/addStatTypeSubCommandGroups';
|
||||||
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
|
||||||
import autocompleteTanks from '../core/discord/autocompleteTanks';
|
import autocompleteTanks from '../core/discord/autocompleteTanks';
|
||||||
import autocompleteUsername from '../core/discord/autocompleteUsername';
|
import autocompleteUsername from '../core/discord/autocompleteUsername';
|
||||||
import interactionToURL from '../core/discord/interactionToURL';
|
import interactionToURL from '../core/discord/interactionToURL';
|
||||||
import linkButton from '../core/discord/linkButton';
|
import linkButton from '../core/discord/linkButton';
|
||||||
import primaryButton from '../core/discord/primaryButton';
|
import primaryButton from '../core/discord/primaryButton';
|
||||||
import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton';
|
import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton';
|
||||||
import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand';
|
import resolvePeriodFromCommand, {
|
||||||
|
ResolvedPeriod,
|
||||||
|
} from '../core/discord/resolvePeriodFromCommand';
|
||||||
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton';
|
import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton';
|
||||||
import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
|
import resolvePlayerFromCommand, {
|
||||||
|
ResolvedPlayer,
|
||||||
|
} from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistryRaw } from '../events/interactionCreate';
|
import { CommandRegistryRaw } from '../events/interactionCreate';
|
||||||
import evolution from '../renderers/evolution';
|
|
||||||
import { AccountInfo } from '../types/accountInfo';
|
import { AccountInfo } from '../types/accountInfo';
|
||||||
|
import { PlayerClanInfo } from '../types/playerClanData';
|
||||||
|
|
||||||
|
async function render(
|
||||||
|
{ region, id }: ResolvedPlayer,
|
||||||
|
{ start, end, name }: ResolvedPeriod,
|
||||||
|
type: 'player' | 'tank',
|
||||||
|
tankId?: number,
|
||||||
|
) {
|
||||||
|
let nameDiscriminator: string | undefined;
|
||||||
|
let image: string | undefined;
|
||||||
|
|
||||||
|
if (type === 'player') {
|
||||||
|
const clan = (
|
||||||
|
await getWargamingResponse<PlayerClanInfo>(
|
||||||
|
`https://api.wotblitz.${region}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`,
|
||||||
|
)
|
||||||
|
)[id]?.clan;
|
||||||
|
|
||||||
|
if (clan) nameDiscriminator = `[${clan.tag}]`;
|
||||||
|
image = clan
|
||||||
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||||
|
: undefined;
|
||||||
|
} else {
|
||||||
|
nameDiscriminator = `(${await resolveTankName(tankId!)})`;
|
||||||
|
image = (await tankopedia)[tankId!]?.images.normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
let histories: Histories;
|
||||||
|
|
||||||
|
if (type === 'player') {
|
||||||
|
histories = await getPlayerHistories(region, id, {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
includeLatestHistories: true,
|
||||||
|
includePreviousHistories: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
histories = await getTankHistories(region, id, {
|
||||||
|
tankId: tankId!,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
includeLatestHistories: true,
|
||||||
|
includePreviousHistories: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const plot = histories.map(
|
||||||
|
(history) =>
|
||||||
|
[
|
||||||
|
history.all.battles,
|
||||||
|
(history.all.wins / history.all.battles) * 100,
|
||||||
|
] as Graph.PlotItem,
|
||||||
|
);
|
||||||
|
const times = histories.map((history) => history.last_battle_time);
|
||||||
|
const minTime = Math.min(...times);
|
||||||
|
const maxTime = Math.max(...times);
|
||||||
|
const ys = plot.map(([, y]) => y);
|
||||||
|
const xs = plot.map(([x]) => x);
|
||||||
|
const maxY = Math.max(...ys);
|
||||||
|
const minY = Math.min(...ys);
|
||||||
|
const maxX = Math.max(...xs);
|
||||||
|
const minX = Math.min(...xs);
|
||||||
|
|
||||||
|
const accountInfo = await getWargamingResponse<AccountInfo>(
|
||||||
|
`https://api.wotblitz.${region}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<TitleBar
|
||||||
|
name={accountInfo[id].nickname}
|
||||||
|
image={image}
|
||||||
|
description={name}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* goofy ahh bug forces me to call them as functions */}
|
||||||
|
{plot.length > 0 && (
|
||||||
|
<Graph.Root
|
||||||
|
verticalMargin={{
|
||||||
|
min: minY,
|
||||||
|
max: maxY,
|
||||||
|
suffix: '%',
|
||||||
|
precision: 2,
|
||||||
|
}}
|
||||||
|
horizontalMargin={{
|
||||||
|
min: minX,
|
||||||
|
max: maxX,
|
||||||
|
precision: 0,
|
||||||
|
}}
|
||||||
|
xMinLabel={new Date(minTime * 1000).toDateString()}
|
||||||
|
xMaxLabel={new Date(maxTime * 1000).toDateString()}
|
||||||
|
>
|
||||||
|
{Graph.Line({
|
||||||
|
// career winrate
|
||||||
|
color: Graph.LineColor.Red,
|
||||||
|
plot: plot,
|
||||||
|
minY,
|
||||||
|
maxY,
|
||||||
|
})}
|
||||||
|
</Graph.Root>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{plot.length === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
@@ -23,7 +133,21 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
|||||||
new SlashCommandBuilder()
|
new SlashCommandBuilder()
|
||||||
.setName('evolution')
|
.setName('evolution')
|
||||||
.setDescription('Evolution of statistics'),
|
.setDescription('Evolution of statistics'),
|
||||||
(option) => option.addStringOption(addUsernameChoices),
|
// (option) =>
|
||||||
|
// option
|
||||||
|
// .addStringOption((option) =>
|
||||||
|
// addStatPropertyOptions(option)
|
||||||
|
// .setName('x')
|
||||||
|
// .setDescription('X axis')
|
||||||
|
// .setRequired(false),
|
||||||
|
// )
|
||||||
|
// .addStringOption((option) =>
|
||||||
|
// addStatPropertyOptions(option)
|
||||||
|
// .setName('y')
|
||||||
|
// .setDescription('Y axis')
|
||||||
|
// .setRequired(false),
|
||||||
|
// )
|
||||||
|
// .addStringOption(addUsernameChoices),
|
||||||
);
|
);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
@@ -56,7 +180,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
await evolution(commandGroup, period, player, tankId),
|
await render(commandGroup, period, player, tankId),
|
||||||
primaryButton(path, 'Refresh'),
|
primaryButton(path, 'Refresh'),
|
||||||
linkButton(
|
linkButton(
|
||||||
`https://www.blitzstars.com/player/${player.region}/${nickname}${
|
`https://www.blitzstars.com/player/${player.region}/${nickname}${
|
||||||
@@ -70,6 +194,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
|||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
autocompleteUsername(interaction);
|
autocompleteUsername(interaction);
|
||||||
autocompleteTanks(interaction);
|
autocompleteTanks(interaction);
|
||||||
|
// autocompleteStatProperty(interaction, 'x');
|
||||||
},
|
},
|
||||||
|
|
||||||
async button(interaction) {
|
async button(interaction) {
|
||||||
@@ -79,7 +204,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
|
|||||||
const player = await resolvePlayerFromButton(interaction);
|
const player = await resolvePlayerFromButton(interaction);
|
||||||
const period = resolvePeriodFromButton(player.region, interaction);
|
const period = resolvePeriodFromButton(player.region, interaction);
|
||||||
|
|
||||||
return await evolution(
|
return await render(
|
||||||
commandGroup,
|
commandGroup,
|
||||||
period,
|
period,
|
||||||
player,
|
player,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { SlashCommandStringOption } from 'discord.js';
|
||||||
|
|
||||||
|
export const STAT_PROPERTIES = [
|
||||||
|
{ name: 'Time', value: 'time' },
|
||||||
|
|
||||||
|
{ name: 'Battles', value: 'battles' },
|
||||||
|
{ name: 'Maximum XP', value: 'max_xp' },
|
||||||
|
{ name: 'Maximum kills', value: 'max_frags' },
|
||||||
|
|
||||||
|
{ name: 'Accumulated spots', value: 'spotted' },
|
||||||
|
{ name: 'Accumulated hits', value: 'hits' },
|
||||||
|
{ name: 'Accumulated kills', value: 'frags' },
|
||||||
|
{ name: 'Accumulated wins', value: 'wins' },
|
||||||
|
{ name: 'Accumulated losses', value: 'losses' },
|
||||||
|
{ name: 'Accumulated capture points', value: 'capture_points' },
|
||||||
|
{ name: 'Accumulated damage dealt', value: 'damage_dealt' },
|
||||||
|
{ name: 'Accumulated damage received', value: 'damage_received' },
|
||||||
|
{ name: 'Accumulated shots', value: 'shots' },
|
||||||
|
{ name: 'Accumulated kills above tier 8', value: 'frags8p' },
|
||||||
|
{ name: 'Accumulated XP', value: 'xp' },
|
||||||
|
{
|
||||||
|
name: 'Accumulated won and survived battles',
|
||||||
|
value: 'win_and_survived',
|
||||||
|
},
|
||||||
|
{ name: 'Accumulated survived battles', value: 'survived_battles' },
|
||||||
|
{
|
||||||
|
name: 'Accumulated dropped capture points',
|
||||||
|
value: 'dropped_capture_points',
|
||||||
|
},
|
||||||
|
|
||||||
|
{ name: 'Average spots', value: 'average_spotted' },
|
||||||
|
{ name: 'Average hits', value: 'average_hits' },
|
||||||
|
{ name: 'Average kills', value: 'average_frags' },
|
||||||
|
{ name: 'Average winrate', value: 'average_wins' },
|
||||||
|
{ name: 'Average loss rate', value: 'average_losses' },
|
||||||
|
{ name: 'Average capture points', value: 'average_capture_points' },
|
||||||
|
{ name: 'Average damage dealt', value: 'average_damage_dealt' },
|
||||||
|
{ name: 'Average damage received', value: 'average_damage_received' },
|
||||||
|
{ name: 'Average shots', value: 'average_shots' },
|
||||||
|
{ name: 'Average kills above tier 8', value: 'average_frags8p' },
|
||||||
|
{ name: 'Average XP', value: 'average_xp' },
|
||||||
|
{
|
||||||
|
name: 'Average win and survival rate',
|
||||||
|
value: 'average_win_and_survived',
|
||||||
|
},
|
||||||
|
{ name: 'Average survival rate', value: 'average_survived_battles' },
|
||||||
|
|
||||||
|
{ name: 'Average WN8', value: 'average_wn8' },
|
||||||
|
{ name: 'Average damage ratio', value: 'average_damage_ratio' },
|
||||||
|
{
|
||||||
|
name: 'Average kills to death ratio',
|
||||||
|
value: 'average_kills_to_death_ratio',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function addStatPropertyOptions(option: SlashCommandStringOption) {
|
||||||
|
return option
|
||||||
|
.setName('stat-property')
|
||||||
|
.setDescription('A specific statistical property')
|
||||||
|
.setAutocomplete(true);
|
||||||
|
}
|
||||||
@@ -25,6 +25,4 @@ export default async function autocompleteClan(
|
|||||||
)
|
)
|
||||||
: [],
|
: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Clan autocomplete for ${focusedOption.value}`);
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { AutocompleteInteraction, CacheType } from 'discord.js';
|
||||||
|
import { go } from 'fuzzysort';
|
||||||
|
import { STAT_PROPERTIES } from '../blitzkrieg/addStatPropertyOptions';
|
||||||
|
|
||||||
|
export default async function autocompleteStatProperty(
|
||||||
|
interaction: AutocompleteInteraction<CacheType>,
|
||||||
|
name = 'stat-property',
|
||||||
|
) {
|
||||||
|
const focusedOption = interaction.options.getFocused(true);
|
||||||
|
if (focusedOption.name !== name) return;
|
||||||
|
|
||||||
|
await interaction.respond(
|
||||||
|
focusedOption.value
|
||||||
|
? go(focusedOption.value, STAT_PROPERTIES, {
|
||||||
|
keys: ['name'],
|
||||||
|
limit: 10,
|
||||||
|
}).map(({ obj }) => obj)
|
||||||
|
: STAT_PROPERTIES.slice(0, 25),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -28,6 +28,4 @@ export default async function autocompleteTanks(
|
|||||||
)
|
)
|
||||||
: [],
|
: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Tanks autocomplete for ${focusedOption.value}`);
|
|
||||||
}
|
}
|
||||||
@@ -25,11 +25,5 @@ export default async function autocompleteUsername(
|
|||||||
)
|
)
|
||||||
: [],
|
: [],
|
||||||
);
|
);
|
||||||
|
} catch (error) {}
|
||||||
console.log(`Username autocomplete for ${focusedOption.value}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(
|
|
||||||
`Failed to autocomplete username for ${focusedOption.value} in time`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import * as Graph from '../components/Graph';
|
|
||||||
import NoData, { NoDataType } from '../components/NoData';
|
|
||||||
import TitleBar from '../components/TitleBar';
|
|
||||||
import Wrapper from '../components/Wrapper';
|
|
||||||
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
|
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse';
|
|
||||||
import resolveTankName from '../core/blitz/resolveTankName';
|
|
||||||
import { tankopedia } from '../core/blitz/tankopedia';
|
|
||||||
import getPlayerHistories from '../core/blitzstars/getPlayerHistories';
|
|
||||||
import getTankHistories from '../core/blitzstars/getTankHistories';
|
|
||||||
import { ResolvedPeriod } from '../core/discord/resolvePeriodFromCommand';
|
|
||||||
import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand';
|
|
||||||
import { AccountInfo } from '../types/accountInfo';
|
|
||||||
import { Histories } from '../types/histories';
|
|
||||||
import { PlayerClanInfo } from '../types/playerClanData';
|
|
||||||
|
|
||||||
export default async function evolution<Type extends StatType>(
|
|
||||||
type: Type,
|
|
||||||
{ start, end, name }: ResolvedPeriod,
|
|
||||||
{ region: server, id }: ResolvedPlayer,
|
|
||||||
tankId: Type extends 'tank' ? number : null,
|
|
||||||
) {
|
|
||||||
let nameDiscriminator: string | undefined;
|
|
||||||
let image: string | undefined;
|
|
||||||
|
|
||||||
if (type === 'player') {
|
|
||||||
const clan = (
|
|
||||||
await getWargamingResponse<PlayerClanInfo>(
|
|
||||||
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`,
|
|
||||||
)
|
|
||||||
)[id]?.clan;
|
|
||||||
|
|
||||||
if (clan) nameDiscriminator = `[${clan.tag}]`;
|
|
||||||
image = clan
|
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
|
||||||
: undefined;
|
|
||||||
} else {
|
|
||||||
nameDiscriminator = `(${await resolveTankName(tankId!)})`;
|
|
||||||
image = (await tankopedia)[tankId!]?.images.normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
let histories: Histories;
|
|
||||||
|
|
||||||
if (type === 'player') {
|
|
||||||
histories = await getPlayerHistories(server, id, {
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
includeLatestHistories: true,
|
|
||||||
includePreviousHistories: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
histories = await getTankHistories(server, id, {
|
|
||||||
tankId: tankId!,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
includeLatestHistories: true,
|
|
||||||
includePreviousHistories: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const plot = histories.map(
|
|
||||||
(history) =>
|
|
||||||
[
|
|
||||||
history.all.battles,
|
|
||||||
(history.all.wins / history.all.battles) * 100,
|
|
||||||
] as Graph.PlotItem,
|
|
||||||
);
|
|
||||||
const times = histories.map((history) => history.last_battle_time);
|
|
||||||
const minTime = Math.min(...times);
|
|
||||||
const maxTime = Math.max(...times);
|
|
||||||
const ys = plot.map(([, y]) => y);
|
|
||||||
const xs = plot.map(([x]) => x);
|
|
||||||
const maxY = Math.max(...ys);
|
|
||||||
const minY = Math.min(...ys);
|
|
||||||
const maxX = Math.max(...xs);
|
|
||||||
const minX = Math.min(...xs);
|
|
||||||
|
|
||||||
const accountInfo = await getWargamingResponse<AccountInfo>(
|
|
||||||
`https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Wrapper>
|
|
||||||
<TitleBar
|
|
||||||
name={accountInfo[id].nickname}
|
|
||||||
image={image}
|
|
||||||
description={name}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* goofy ahh bug forces me to call them as functions */}
|
|
||||||
{plot.length > 0 && (
|
|
||||||
<Graph.Root
|
|
||||||
verticalMargin={{
|
|
||||||
min: minY,
|
|
||||||
max: maxY,
|
|
||||||
suffix: '%',
|
|
||||||
precision: 2,
|
|
||||||
}}
|
|
||||||
horizontalMargin={{
|
|
||||||
min: minX,
|
|
||||||
max: maxX,
|
|
||||||
precision: 0,
|
|
||||||
}}
|
|
||||||
xMinLabel={new Date(minTime * 1000).toDateString()}
|
|
||||||
xMaxLabel={new Date(maxTime * 1000).toDateString()}
|
|
||||||
>
|
|
||||||
{Graph.Line({
|
|
||||||
// career winrate
|
|
||||||
color: Graph.LineColor.Red,
|
|
||||||
plot: plot,
|
|
||||||
minY,
|
|
||||||
maxY,
|
|
||||||
})}
|
|
||||||
</Graph.Root>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{plot.length === 0 && <NoData type={NoDataType.BattlesInPeriod} />}
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user