mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
feat: extracted evolution renderer
This commit is contained in:
1 parent
752f9b339b
commit
d8a78bc25e
4 files changed
+166
-152
No files matched your search
+21
-149
@@ -1,35 +1,17 @@
|
|||||||
import { ButtonBuilder, ButtonStyle, SlashCommandBuilder } from 'discord.js';
|
import { SlashCommandBuilder } from 'discord.js';
|
||||||
import * as Graph from '../components/Graph/index.js';
|
|
||||||
import NoData, { NoDataType } from '../components/NoData.js';
|
|
||||||
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
|
||||||
import TitleBar from '../components/TitleBar.js';
|
|
||||||
import Wrapper from '../components/Wrapper.js';
|
|
||||||
import { BLITZ_SERVERS } from '../constants/servers.js';
|
|
||||||
import tanksAutocomplete from '../core/autocomplete/tanks.js';
|
import tanksAutocomplete from '../core/autocomplete/tanks.js';
|
||||||
import usernameAutocomplete from '../core/autocomplete/username.js';
|
import usernameAutocomplete from '../core/autocomplete/username.js';
|
||||||
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
|
||||||
import resolveTankId from '../core/blitz/resolveTankId.js';
|
import resolveTankId from '../core/blitz/resolveTankId.js';
|
||||||
import resolveTankName from '../core/blitz/resolveTankName.js';
|
|
||||||
import { tankopedia } from '../core/blitz/tankopedia.js';
|
|
||||||
import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js';
|
|
||||||
import getTankHistories from '../core/blitzstars/getTankHistories.js';
|
|
||||||
import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js';
|
|
||||||
import {
|
|
||||||
Period,
|
|
||||||
RELATIVE_PERIOD_NAMES,
|
|
||||||
} from '../core/options/addPeriodSubCommands.js';
|
|
||||||
import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js';
|
import addStatsSubCommandGroups from '../core/options/addStatsSubCommandGroups.js';
|
||||||
import resolvePeriod from '../core/options/resolvePeriod.js';
|
import resolvePeriod from '../core/options/resolvePeriod.js';
|
||||||
import resolvePlayer from '../core/options/resolvePlayer.js';
|
import resolvePlayer from '../core/options/resolvePlayer.js';
|
||||||
import { WARGAMING_APPLICATION_ID } from '../core/process/args.js';
|
|
||||||
import { CommandRegistry } from '../events/interactionCreate.js';
|
import { CommandRegistry } from '../events/interactionCreate.js';
|
||||||
import { AccountInfo } from '../types/accountInfo.js';
|
import evolution from '../renderers/evolution.js';
|
||||||
import { Histories } from '../types/histories.js';
|
import { StatType } from '../renderers/stats.js';
|
||||||
import { PlayerClanData } from '../types/playerClanData.js';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inProduction: true,
|
inProduction: true,
|
||||||
inDevelopment: false,
|
inDevelopment: true,
|
||||||
inPublic: true,
|
inPublic: true,
|
||||||
|
|
||||||
command: addStatsSubCommandGroups(
|
command: addStatsSubCommandGroups(
|
||||||
@@ -39,136 +21,26 @@ export default {
|
|||||||
),
|
),
|
||||||
|
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
const commandGroup = interaction.options.getSubcommandGroup()!;
|
const commandGroup = interaction.options.getSubcommandGroup(
|
||||||
const { id, server } = await resolvePlayer(interaction);
|
true,
|
||||||
let nameDiscriminator: string | undefined;
|
) as StatType;
|
||||||
let image: string | undefined;
|
const player = await resolvePlayer(interaction);
|
||||||
|
const period = resolvePeriod(interaction);
|
||||||
const tankIdRaw = interaction.options.getString('tank')!;
|
const tankIdRaw = interaction.options.getString('tank')!;
|
||||||
let tankId: number;
|
const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : 0;
|
||||||
|
|
||||||
if (commandGroup === 'player') {
|
return await evolution(commandGroup, period, player, tankId);
|
||||||
const clan = (
|
|
||||||
await getWargamingResponse<PlayerClanData>(
|
|
||||||
`https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`,
|
|
||||||
)
|
|
||||||
)[id]?.clan;
|
|
||||||
|
|
||||||
if (clan) nameDiscriminator = `[${clan.tag}]`;
|
// new ButtonBuilder()
|
||||||
image = clan
|
// .setStyle(ButtonStyle.Link)
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
// .setLabel('View on BlitzStars')
|
||||||
: undefined;
|
// .setURL(
|
||||||
} else if (commandGroup === 'tank') {
|
// commandGroup === 'tank'
|
||||||
tankId = resolveTankId(tankIdRaw);
|
// ? `https://www.blitzstars.com/player/com/${
|
||||||
nameDiscriminator = `(${resolveTankName(tankId)})`;
|
// accountInfo[id].nickname
|
||||||
image = tankopedia[tankId].images.normal;
|
// }/tank/${tankId!}`
|
||||||
}
|
// : `https://www.blitzstars.com/player/com/${accountInfo[id].nickname}`,
|
||||||
|
// );
|
||||||
let histories: Histories;
|
|
||||||
|
|
||||||
const { evolutionName, start, end } = resolvePeriod(interaction);
|
|
||||||
|
|
||||||
if (commandGroup === 'player') {
|
|
||||||
histories = await getPlayerHistories(server, id, {
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
includeLatestHistories: true,
|
|
||||||
includePreviousHistories: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const tankId = resolveTankId(tankIdRaw);
|
|
||||||
histories = await getTankHistories(server, id, {
|
|
||||||
tankId,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
includeLatestHistories: true,
|
|
||||||
includePreviousHistories: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const careerWinrate = histories.map(
|
|
||||||
(history) =>
|
|
||||||
[
|
|
||||||
history.last_battle_time,
|
|
||||||
(history.all.wins / history.all.battles) * 100,
|
|
||||||
] as Graph.PlotItem,
|
|
||||||
);
|
|
||||||
const careerBattles = histories.map(
|
|
||||||
(history) =>
|
|
||||||
[history.last_battle_time, history.all.battles] as Graph.PlotItem,
|
|
||||||
);
|
|
||||||
const winrateYs = careerWinrate.map(([, y]) => y);
|
|
||||||
const maxWinrate = Math.max(...winrateYs);
|
|
||||||
const minWinrate = Math.min(...winrateYs);
|
|
||||||
const battleYs = careerBattles.map(([, y]) => y);
|
|
||||||
const maxBattle = Math.max(...battleYs);
|
|
||||||
const minBattle = Math.min(...battleYs);
|
|
||||||
|
|
||||||
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}
|
|
||||||
nameDiscriminator={nameDiscriminator}
|
|
||||||
image={image}
|
|
||||||
description={`${evolutionName} • ${new Date().toDateString()} • ${
|
|
||||||
BLITZ_SERVERS[server]
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* goofy ahh bug forces me to call them as functions */}
|
|
||||||
{careerWinrate.length > 0 && (
|
|
||||||
<Graph.Root
|
|
||||||
xMinLabel={
|
|
||||||
RELATIVE_PERIOD_NAMES[
|
|
||||||
interaction.options.getSubcommand() as Period
|
|
||||||
]
|
|
||||||
}
|
|
||||||
xMaxLabel="Latest recorded battle"
|
|
||||||
leftVerticalMargin={{
|
|
||||||
min: minWinrate,
|
|
||||||
max: maxWinrate,
|
|
||||||
suffix: '%',
|
|
||||||
}}
|
|
||||||
rightVerticalMargin={{
|
|
||||||
min: minBattle,
|
|
||||||
max: maxBattle,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{Graph.Line({
|
|
||||||
// total battles
|
|
||||||
plot: careerBattles!,
|
|
||||||
color: Graph.LineColor.Blue,
|
|
||||||
})}
|
|
||||||
{Graph.Line({
|
|
||||||
// career winrate
|
|
||||||
plot: careerWinrate!,
|
|
||||||
minY: minWinrate,
|
|
||||||
maxY: maxWinrate,
|
|
||||||
})}
|
|
||||||
</Graph.Root>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{careerWinrate.length === 0 && (
|
|
||||||
<NoData type={NoDataType.BattlesInPeriod} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<PoweredByBlitzStars />
|
|
||||||
</Wrapper>,
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setStyle(ButtonStyle.Link)
|
|
||||||
.setLabel('View on BlitzStars')
|
|
||||||
.setURL(
|
|
||||||
commandGroup === 'tank'
|
|
||||||
? `https://www.blitzstars.com/player/com/${
|
|
||||||
accountInfo[id].nickname
|
|
||||||
}/tank/${tankId!}`
|
|
||||||
: `https://www.blitzstars.com/player/com/${accountInfo[id].nickname}`,
|
|
||||||
),
|
|
||||||
supportBlitzStars,
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
|
|||||||
@@ -88,5 +88,5 @@ export default async function getPlayerHistories(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...previousNodes, ...filtered, ...latestNodes] satisfies Histories;
|
return [...latestNodes, ...filtered, ...previousNodes] satisfies Histories;
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
|||||||
import getPeriodNow from '../blitzstars/getPeriodNow.js';
|
import getPeriodNow from '../blitzstars/getPeriodNow.js';
|
||||||
import getPeriodStart from '../blitzstars/getPeriodStart.js';
|
import getPeriodStart from '../blitzstars/getPeriodStart.js';
|
||||||
import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js';
|
import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo.js';
|
||||||
import { Period } from './addPeriodSubCommands.js';
|
import { Period, RELATIVE_PERIOD_NAMES } from './addPeriodSubCommands.js';
|
||||||
|
|
||||||
export const PERIOD_NAMES: Record<Period, string> = {
|
export const PERIOD_NAMES: Record<Period, string> = {
|
||||||
today: "Today's statistics",
|
today: "Today's statistics",
|
||||||
@@ -23,6 +23,7 @@ export const EVOLUTION_PERIOD_NAMES: Record<Period, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface ResolvedPeriod {
|
export interface ResolvedPeriod {
|
||||||
|
relativePeriodName: string;
|
||||||
statsName: string;
|
statsName: string;
|
||||||
evolutionName: string;
|
evolutionName: string;
|
||||||
start: number;
|
start: number;
|
||||||
@@ -37,6 +38,8 @@ export default function resolvePeriod(
|
|||||||
let evolutionName: string;
|
let evolutionName: string;
|
||||||
let start: number;
|
let start: number;
|
||||||
let end: number;
|
let end: number;
|
||||||
|
const relativePeriodName =
|
||||||
|
RELATIVE_PERIOD_NAMES[interaction.options.getSubcommand() as Period];
|
||||||
|
|
||||||
if (period === 'custom') {
|
if (period === 'custom') {
|
||||||
const startRaw = interaction.options.getInteger('start')!;
|
const startRaw = interaction.options.getInteger('start')!;
|
||||||
@@ -55,5 +58,11 @@ export default function resolvePeriod(
|
|||||||
end = getPeriodNow();
|
end = getPeriodNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { statsName, evolutionName, start, end } satisfies ResolvedPeriod;
|
return {
|
||||||
|
statsName,
|
||||||
|
evolutionName,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
relativePeriodName,
|
||||||
|
} satisfies ResolvedPeriod;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import * as Graph from '../components/Graph/index.js';
|
||||||
|
import NoData, { NoDataType } from '../components/NoData.js';
|
||||||
|
import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js';
|
||||||
|
import TitleBar from '../components/TitleBar.js';
|
||||||
|
import Wrapper from '../components/Wrapper.js';
|
||||||
|
import { BLITZ_SERVERS } from '../constants/servers.js';
|
||||||
|
import getWargamingResponse from '../core/blitz/getWargamingResponse.js';
|
||||||
|
import resolveTankName from '../core/blitz/resolveTankName.js';
|
||||||
|
import { tankopedia } from '../core/blitz/tankopedia.js';
|
||||||
|
import getPlayerHistories from '../core/blitzstars/getPlayerHistories.js';
|
||||||
|
import getTankHistories from '../core/blitzstars/getTankHistories.js';
|
||||||
|
import { ResolvedPeriod } from '../core/options/resolvePeriod.js';
|
||||||
|
import { ResolvedPlayer } from '../core/options/resolvePlayer.js';
|
||||||
|
import { WARGAMING_APPLICATION_ID } from '../core/process/args.js';
|
||||||
|
import { AccountInfo } from '../types/accountInfo.js';
|
||||||
|
import { Histories } from '../types/histories.js';
|
||||||
|
import { PlayerClanData } from '../types/playerClanData.js';
|
||||||
|
import { StatType } from './stats.js';
|
||||||
|
|
||||||
|
export default async function evolution<Type extends StatType>(
|
||||||
|
type: Type,
|
||||||
|
{ start, end, evolutionName, relativePeriodName }: ResolvedPeriod,
|
||||||
|
{ server, id }: ResolvedPlayer,
|
||||||
|
tankId: Type extends 'tank' ? number : never,
|
||||||
|
) {
|
||||||
|
let nameDiscriminator: string | undefined;
|
||||||
|
let image: string | undefined;
|
||||||
|
|
||||||
|
if (type === 'player') {
|
||||||
|
const clan = (
|
||||||
|
await getWargamingResponse<PlayerClanData>(
|
||||||
|
`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 = `(${resolveTankName(tankId)})`;
|
||||||
|
image = 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,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
includeLatestHistories: true,
|
||||||
|
includePreviousHistories: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const careerWinrate = histories.map(
|
||||||
|
(history) =>
|
||||||
|
[
|
||||||
|
history.last_battle_time,
|
||||||
|
(history.all.wins / history.all.battles) * 100,
|
||||||
|
] as Graph.PlotItem,
|
||||||
|
);
|
||||||
|
const careerBattles = histories.map(
|
||||||
|
(history) =>
|
||||||
|
[history.last_battle_time, history.all.battles] as Graph.PlotItem,
|
||||||
|
);
|
||||||
|
const winrateYs = careerWinrate.map(([, y]) => y);
|
||||||
|
const maxWinrate = Math.max(...winrateYs);
|
||||||
|
const minWinrate = Math.min(...winrateYs);
|
||||||
|
const battleYs = careerBattles.map(([, y]) => y);
|
||||||
|
const maxBattle = Math.max(...battleYs);
|
||||||
|
const minBattle = Math.min(...battleYs);
|
||||||
|
|
||||||
|
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}
|
||||||
|
nameDiscriminator={nameDiscriminator}
|
||||||
|
image={image}
|
||||||
|
description={`${evolutionName} • ${new Date().toDateString()} • ${
|
||||||
|
BLITZ_SERVERS[server]
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* goofy ahh bug forces me to call them as functions */}
|
||||||
|
{careerWinrate.length > 0 && (
|
||||||
|
<Graph.Root
|
||||||
|
xMinLabel={relativePeriodName}
|
||||||
|
xMaxLabel="Latest recorded battle" // TODO: this is not true in custom periods
|
||||||
|
leftVerticalMargin={{
|
||||||
|
min: minWinrate,
|
||||||
|
max: maxWinrate,
|
||||||
|
suffix: '%',
|
||||||
|
}}
|
||||||
|
rightVerticalMargin={{
|
||||||
|
min: minBattle,
|
||||||
|
max: maxBattle,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Graph.Line({
|
||||||
|
// total battles
|
||||||
|
plot: careerBattles!,
|
||||||
|
color: Graph.LineColor.Blue,
|
||||||
|
})}
|
||||||
|
{Graph.Line({
|
||||||
|
// career winrate
|
||||||
|
plot: careerWinrate!,
|
||||||
|
minY: minWinrate,
|
||||||
|
maxY: maxWinrate,
|
||||||
|
})}
|
||||||
|
</Graph.Root>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{careerWinrate.length === 0 && (
|
||||||
|
<NoData type={NoDataType.BattlesInPeriod} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<PoweredByBlitzStars />
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user