From f801783358bde02e49980888a58afd8196ae8316 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Fri, 2 Jun 2023 01:31:14 +0000 Subject: [PATCH] feat: added WN8 to /today --- src/commands/debug.ts | 2 +- src/commands/stats.tsx | 2 +- src/commands/tankstats.tsx | 2 +- src/commands/today.tsx | 117 ++++++++++++++---- src/components/Breakdown/components/Row.tsx | 17 ++- .../Breakdown/components/RowStat.tsx | 16 ++- src/components/GenericAllStats.tsx | 4 +- .../components/GenericStatsRow.tsx | 2 +- src/components/GenericStats/index.tsx | 8 +- src/components/Wrapper.tsx | 22 +++- src/core/blitzstars/playerAverage.ts | 12 ++ .../{tankaverages.ts => tankAverages.ts} | 0 src/core/interaction/cleanTable.ts | 2 +- src/core/ui/render.tsx | 8 +- 14 files changed, 163 insertions(+), 51 deletions(-) create mode 100644 src/core/blitzstars/playerAverage.ts rename src/core/blitzstars/{tankaverages.ts => tankAverages.ts} (100%) diff --git a/src/commands/debug.ts b/src/commands/debug.ts index a33a18f1f..e7630f90d 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import packageJSON from '../../package.json' assert { type: 'json' }; import { tankopedia } from '../core/blitz/tankopedia.js'; -import { tankAverages } from '../core/blitzstars/tankaverages.js'; +import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cleanTable from '../core/interaction/cleanTable.js'; import cmdName from '../core/interaction/cmdName.js'; import infoEmbed from '../core/interaction/infoEmbed.js'; diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 3a7304f8e..ee6e30b45 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -18,7 +18,7 @@ import { tankopedia } from '../core/blitz/tankopedia.js'; import getPeriodNow from '../core/blitzstars/getPeriodNow.js'; import getPeriodicStart from '../core/blitzstars/getPeriodStart.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; -import { tankAverages } from '../core/blitzstars/tankaverages.js'; +import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cmdName from '../core/interaction/cmdName.js'; import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js'; import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js'; diff --git a/src/commands/tankstats.tsx b/src/commands/tankstats.tsx index 0e4854ffa..17c55a548 100644 --- a/src/commands/tankstats.tsx +++ b/src/commands/tankstats.tsx @@ -22,7 +22,7 @@ import getPeriodicStart from '../core/blitzstars/getPeriodStart.js'; import getTankStatsOverTime, { emptyAllStats, } from '../core/blitzstars/getTankStatsOverTime.js'; -import { tankAverages } from '../core/blitzstars/tankaverages.js'; +import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cmdName from '../core/interaction/cmdName.js'; import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js'; import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js'; diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 0fd76e2e6..d9ac2539a 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -7,18 +7,21 @@ import * as Breakdown from '../components/Breakdown/index.js'; import NoBattlesInPeriod from '../components/NoBattlesInPeriod.js'; import PoweredByBlitzStars from '../components/PoweredByBlitzStars.js'; import TitleBar from '../components/TitleBar.js'; -import Wrapper from '../components/Wrapper.js'; +import Wrapper, { WrapperSize } from '../components/Wrapper.js'; import { BLITZ_SERVERS } from '../constants/servers.js'; import usernameAutocomplete from '../core/autocomplete/username.js'; import getBlitzAccount from '../core/blitz/getBlitzAccount.js'; +import getWN8 from '../core/blitz/getWN8.js'; import getWargamingResponse from '../core/blitz/getWargamingResponse.js'; import resolveTankName from '../core/blitz/resolveTankName.js'; import sumStats from '../core/blitz/sumStats.js'; import { tankopedia } from '../core/blitz/tankopedia.js'; import getTankStatsOverTime from '../core/blitzstars/getTankStatsOverTime.js'; import last5AM from '../core/blitzstars/last5AM.js'; +import { tankAverages } from '../core/blitzstars/tankAverages.js'; import cmdName from '../core/interaction/cmdName.js'; import fullBlitzStarsStats from '../core/interaction/fullBlitzStarsStats.js'; +import infoEmbed from '../core/interaction/infoEmbed.js'; import { supportBlitzStars } from '../core/interaction/supportBlitzStars.js'; import addUsernameOption from '../core/options/addUsernameOption.js'; import { args } from '../core/process/args.js'; @@ -75,36 +78,88 @@ export default { tankStatsOverTime[0] = accumulatedStats; } - const rows = Object.entries(tankStatsOverTime).map( - ([tankId, tankStats]) => { - const career = careerStats[tankId as unknown as number]; + const tankStatsOverTimeEntries = Object.entries(tankStatsOverTime); + const todayWN8s = tankStatsOverTimeEntries.reduce>( + (accumulator, [tankIdString, tankStats]) => { + const tankId = Number(tankIdString); - return ( - - ); + return tankId === 0 + ? accumulator + : { + ...accumulator, + [tankId]: getWN8(tankAverages[tankId].all, tankStats), + }; }, + {}, ); + const careerWN8s = tankStatsOverTimeEntries.reduce>( + (accumulator, [tankIdString, tankStats]) => { + const tankId = Number(tankIdString); + + return tankId === 0 + ? accumulator + : { + ...accumulator, + [tankId]: getWN8(tankAverages[tankId].all, careerStats[tankId]), + }; + }, + {}, + ); + const todayWN8sEntries = Object.entries(todayWN8s); + const careerWN8sEntries = Object.entries(careerWN8s); + + todayWN8s[0] = + todayWN8sEntries.reduce( + (accumulator, [tankIdString, wn8]) => + accumulator + wn8 * tankStatsOverTime[Number(tankIdString)].battles, + 0, + ) / + todayWN8sEntries.reduce( + (accumulator, [tankIdString]) => + accumulator + tankStatsOverTime[Number(tankIdString)].battles, + 0, + ); + careerWN8s[0] = + careerWN8sEntries.reduce( + (accumulator, [tankIdString, wn8]) => + accumulator + wn8 * careerStats[Number(tankIdString)].battles, + 0, + ) / + careerWN8sEntries.reduce( + (accumulator, [tankIdString]) => + accumulator + careerStats[Number(tankIdString)].battles, + 0, + ); + + const rows = tankStatsOverTimeEntries.map(([tankIdString, tankStats]) => { + const tankId = Number(tankIdString); + const career = careerStats[tankId]; + + return ( + + ); + }); const image = await render( - + , + WrapperSize.Roomy, ); const actionRow = new ActionRowBuilder().addComponents( @@ -133,6 +189,15 @@ export default { ); await interaction.editReply({ + embeds: + rows.length >= 6 + ? [ + infoEmbed( + 'Very large image!', + 'Zoom in or click "Open in Browser."', + ), + ] + : undefined, files: [image], components: [actionRow], }); diff --git a/src/components/Breakdown/components/Row.tsx b/src/components/Breakdown/components/Row.tsx index 29cfc00ec..0d5f8e125 100644 --- a/src/components/Breakdown/components/Row.tsx +++ b/src/components/Breakdown/components/Row.tsx @@ -1,3 +1,4 @@ +import getWN8Percentile from '../../../core/blitz/getWN8Percentile.js'; import { RowDiscriminator } from './RowDiscriminator.js'; import { RowStat } from './RowStat.js'; @@ -22,8 +23,8 @@ export function Row({ careerWinrate, WN8, careerWN8, - damage: averageDamage, - careerDamage: careerAverageDamage, + damage, + careerDamage, survival, careerSurvival, battles, @@ -39,11 +40,17 @@ export function Row({ career={`${(careerWinrate * 100).toFixed(2)}%`} delta={winrate - careerWinrate} /> + - {delta !== undefined && delta !== 0 && ( + {percentile === undefined && delta !== undefined && delta !== 0 && ( 0 @@ -41,6 +50,9 @@ export function RowStat({ name, value, career, delta }: RowStatProps) { style={{ width: 12, height: 12 }} /> )} + {percentile !== undefined && ( + + )} - {stat[2] && } + {stat[2] !== undefined && } {stat[1]} diff --git a/src/components/GenericStats/index.tsx b/src/components/GenericStats/index.tsx index d85239537..94414baad 100644 --- a/src/components/GenericStats/index.tsx +++ b/src/components/GenericStats/index.tsx @@ -2,8 +2,8 @@ import { Percentile } from '../../constants/percentiles.js'; import GenericStatsColumn from './components/GenericStatsColumn.js'; export type Stat = - | [string, string | number] - | [string, string | number, Percentile | undefined]; + | [string, string | number | undefined] + | [string, string | number | undefined, Percentile | undefined]; export interface GenericStatsProps { stats: Stat[]; @@ -14,9 +14,7 @@ export default function GenericStats({ stats, columnCount = 2, }: GenericStatsProps) { - const filteredStats = stats.filter( - ([, value]) => `${value}` !== `${-Infinity}`, - ); + const filteredStats = stats.filter(([, value]) => value !== undefined); const itemsPerRow = Math.ceil(filteredStats.length / columnCount); const columns: Stat[][] = []; diff --git a/src/components/Wrapper.tsx b/src/components/Wrapper.tsx index 15d51f1c2..9689b4bd3 100644 --- a/src/components/Wrapper.tsx +++ b/src/components/Wrapper.tsx @@ -1,11 +1,25 @@ import { ReactNode } from 'react'; import { theme } from '../stitches.config.js'; -export interface WrapperProps { - children: ReactNode; +export enum WrapperSize { + Regular, + Roomy, } -export default function Wrapper({ children }: WrapperProps) { +export interface WrapperProps { + children: ReactNode; + size?: WrapperSize; +} + +export const WRAPPER_SIZE_WIDTHS: Record = { + [WrapperSize.Regular]: 640, + [WrapperSize.Roomy]: 800, +}; + +export default function Wrapper({ + children, + size = WrapperSize.Regular, +}: WrapperProps) { return (
{ + return sumStats([accumulator, tankAverage.all]); + }, + emptyAllStats, +); +console.log('Calculated player average'); diff --git a/src/core/blitzstars/tankaverages.ts b/src/core/blitzstars/tankAverages.ts similarity index 100% rename from src/core/blitzstars/tankaverages.ts rename to src/core/blitzstars/tankAverages.ts diff --git a/src/core/interaction/cleanTable.ts b/src/core/interaction/cleanTable.ts index 7939453cc..45961433c 100644 --- a/src/core/interaction/cleanTable.ts +++ b/src/core/interaction/cleanTable.ts @@ -3,7 +3,7 @@ export type TableInput = TableInputEntry[]; export default function cleanTable(input: TableInput) { return input - .filter((array) => array[1] !== `${-Infinity}`) + .filter((array) => array[1] !== undefined) .map((array) => (array.length === 0 ? '' : `**${array[0]}**: ${array[1]}`)) .join('\n'); } diff --git a/src/core/ui/render.tsx b/src/core/ui/render.tsx index 10afb44ef..6100c1793 100644 --- a/src/core/ui/render.tsx +++ b/src/core/ui/render.tsx @@ -2,6 +2,7 @@ import { Resvg } from '@resvg/resvg-js'; import { readFile } from 'fs'; import { ReactNode } from 'react'; import satori from 'satori'; +import { WRAPPER_SIZE_WIDTHS, WrapperSize } from '../../components/Wrapper.js'; const FONT_NAME = 'Roboto'; const FONT_FILES = ['Roboto', 'Roboto-Bold', 'Roboto-Black']; @@ -20,9 +21,12 @@ const [robotoFlex, robotoFlexBold, robotoFlexBlack] = await Promise.all( ); console.log('Fonts imported'); -export default async function render(element: ReactNode) { +export default async function render( + element: ReactNode, + size: WrapperSize = WrapperSize.Regular, +) { const svg = await satori(element, { - width: 640, + width: WRAPPER_SIZE_WIDTHS[size], fonts: [ { data: robotoFlex, name: FONT_NAME, weight: 400 }, { data: robotoFlexBold, name: FONT_NAME, weight: 700 },