feat: added future features 👀

This commit is contained in:
TrèsAbhi committed 2023-10-11 20:18:51 -05:00
1 parent 0db96795b3
commit db976c4ae9
7 files changed
+214 -138

No files matched your search

+132 -7
View File
@@ -2,20 +2,130 @@ import { SlashCommandBuilder } from 'discord.js';
import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID';
import getWargamingResponse from '../core/blitz/getWargamingResponse';
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 addUsernameChoices from '../core/discord/addUsernameChoices';
import autocompleteTanks from '../core/discord/autocompleteTanks';
import autocompleteUsername from '../core/discord/autocompleteUsername';
import interactionToURL from '../core/discord/interactionToURL';
import linkButton from '../core/discord/linkButton';
import primaryButton from '../core/discord/primaryButton';
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 resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand';
import resolvePlayerFromCommand, {
ResolvedPlayer,
} from '../core/discord/resolvePlayerFromCommand';
import { CommandRegistryRaw } from '../events/interactionCreate';
import evolution from '../renderers/evolution';
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>(
async (resolve) => {
@@ -23,7 +133,21 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
new SlashCommandBuilder()
.setName('evolution')
.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({
@@ -56,7 +180,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
});
return [
await evolution(commandGroup, period, player, tankId),
await render(commandGroup, period, player, tankId),
primaryButton(path, 'Refresh'),
linkButton(
`https://www.blitzstars.com/player/${player.region}/${nickname}${
@@ -70,6 +194,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
autocomplete: (interaction) => {
autocompleteUsername(interaction);
autocompleteTanks(interaction);
// autocompleteStatProperty(interaction, 'x');
},
async button(interaction) {
@@ -79,7 +204,7 @@ export const evolutionCommand = new Promise<CommandRegistryRaw>(
const player = await resolvePlayerFromButton(interaction);
const period = resolvePeriodFromButton(player.region, interaction);
return await evolution(
return await render(
commandGroup,
period,
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);
}
-2
View File
@@ -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),
);
}
-2
View File
@@ -28,6 +28,4 @@ export default async function autocompleteTanks(
)
: [],
);
console.log(`Tanks autocomplete for ${focusedOption.value}`);
}
+1 -7
View File
@@ -25,11 +25,5 @@ export default async function autocompleteUsername(
)
: [],
);
console.log(`Username autocomplete for ${focusedOption.value}`);
} catch (error) {
console.warn(
`Failed to autocomplete username for ${focusedOption.value} in time`,
);
}
} catch (error) {}
}
-120
View File
@@ -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>
);
}