From c24639dd0ccac3c3dd1148ca6f911e4f2a76375d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 1 May 2024 20:54:27 -0500 Subject: [PATCH] feat: deltas --- src/app/embeds/session/page.tsx | 338 -------------------------- src/app/tools/session/page.tsx | 153 ++++++------ src/components/Navbar/index.tsx | 9 +- src/core/statistics/deltaTankStats.ts | 103 ++++---- src/stores/session.ts | 2 + 5 files changed, 128 insertions(+), 477 deletions(-) delete mode 100644 src/app/embeds/session/page.tsx diff --git a/src/app/embeds/session/page.tsx b/src/app/embeds/session/page.tsx deleted file mode 100644 index 9d1ae0076..000000000 --- a/src/app/embeds/session/page.tsx +++ /dev/null @@ -1,338 +0,0 @@ -'use client'; - -import { ContextMenu } from '@radix-ui/themes'; -import { useEffect, useState } from 'react'; -import * as Breakdown from '../../../components/Breakdown'; -import fetchBlitz from '../../../core/blitz/fetchBlitz'; -import { resetSession } from '../../../core/blitzkit/resetSession'; -import { - TankDefinition, - tankDefinitions, -} from '../../../core/blitzkit/tankDefinitions'; -import { tankAverages } from '../../../core/blitzstars/tankAverages'; -import calculateWN8 from '../../../core/statistics/calculateWN8'; -import { deltaTankStats } from '../../../core/statistics/deltaTankStats'; -import getWN8Percentile from '../../../core/statistics/getWN8Percentile'; -import mutateSession, { useSession } from '../../../stores/session'; -import { IndividualTankStats, TanksStats } from '../../../types/tanksStats'; -import { CustomColumnDisplay } from '../../tools/session/components/CustomColumn'; -import { Menu } from '../../tools/session/components/Menu'; - -const REFRESH_RATE = 1 / 5; - -interface SessionPageProps { - naked?: boolean; -} - -export default function SessionPage({ naked = true }: SessionPageProps) { - const session = useSession(); - const since = session.isTracking ? new Date(session.time) : undefined; - const [diff, setDiff] = useState< - | { - careerWN8: number; - - list: { - stats: IndividualTankStats; - tankDefinitions?: TankDefinition; - career: IndividualTankStats; - currentWN8?: number; - careerWN8?: number; - }[]; - } - | undefined - >(undefined); - const sessionBattles = diff?.list.reduce( - (accumulator, { stats }) => accumulator + stats.all.battles, - 0, - ); - const tankStatsArray = session.isTracking - ? (Object.values(session.tankStats) as IndividualTankStats[]) - : []; - const sessionWinrate = diff - ? diff.list.reduce( - (accumulator, { stats }) => accumulator + stats.all.wins, - 0, - ) / sessionBattles! - : 0; - const careerBattles = tankStatsArray.reduce( - (accumulator, stats) => accumulator + stats.all.battles, - 0, - ); - const careerWinrate = - tankStatsArray.reduce( - (accumulator, stats) => accumulator + stats.all.wins, - 0, - ) / careerBattles; - const currentDamage = diff - ? diff.list.reduce( - (accumulator, { stats }) => accumulator + stats.all.damage_dealt, - 0, - ) / sessionBattles! - : 0; - const careerDamage = - tankStatsArray.reduce( - (accumulator, stats) => accumulator + stats.all.damage_dealt, - 0, - ) / careerBattles; - - useEffect(() => { - if (session.title === 'Untitled session') { - mutateSession((draft) => { - if (draft.isTracking) draft.title = draft.nickname; - }); - } - }, [session.title]); - - useEffect(() => { - async function recalculateDiff() { - if (session.isTracking) { - const { id, region } = session; - const careerRaw = await fetchBlitz(region, 'tanks/stats', { - account_id: id, - }); - const career = careerRaw[id]!.reduce< - Record - >( - (accumulator, curr) => ({ - ...accumulator, - [curr.tank_id]: curr, - }), - {}, - ); - const awaitedTankDefinitions = await tankDefinitions; - const awaitedTankAverages = await tankAverages; - const careerWN8 = - careerRaw[id]!.reduce( - (accumulator, { tank_id, all }) => - accumulator + - (awaitedTankAverages[tank_id] && all.battles > 0 - ? all.battles * - calculateWN8(awaitedTankAverages[tank_id].all, all) - : 0), - 0, - ) / - careerRaw[id]!.reduce( - (accumulator, { tank_id, all }) => - accumulator + - (awaitedTankAverages[tank_id] && all.battles > 0 - ? all.battles - : 0), - 0, - ); - - setDiff({ - careerWN8, - - list: ( - Object.values( - deltaTankStats(session.tankStats, career, session.time / 1000), - ) as IndividualTankStats[] - ).map((stats) => { - return { - stats, - tankDefinitions: awaitedTankDefinitions[stats.tank_id], - career: career[stats.tank_id], - currentWN8: awaitedTankAverages[stats.tank_id] - ? calculateWN8( - awaitedTankAverages[stats.tank_id].all, - stats.all, - ) - : undefined, - careerWN8: awaitedTankAverages[stats.tank_id] - ? calculateWN8( - awaitedTankAverages[stats.tank_id].all, - career[stats.tank_id].all, - ) - : undefined, - }; - }), - }); - } - } - - recalculateDiff(); - const interval = setInterval(recalculateDiff, 1000 / REFRESH_RATE); - - return () => clearInterval(interval); - }, [session]); - - const totalRowStats: Record< - CustomColumnDisplay, - Breakdown.RowStatItem | undefined - > = { - battles: { - title: 'Battles', - current: sessionBattles?.toLocaleString(), - career: tankStatsArray - .reduce((accumulator, stats) => accumulator + stats.all.battles, 0) - .toLocaleString(), - }, - winrate: { - title: 'Winrate', - current: sessionBattles ? `${(100 * sessionWinrate).toFixed(2)}%` : '--', - career: `${(100 * careerWinrate).toFixed(2)}%`, - delta: sessionBattles === 0 ? 0 : sessionWinrate - careerWinrate, - }, - wn8: (() => { - if (!diff) return undefined; - - const battlesWithWN8 = diff.list.reduce( - (accumulator, { currentWN8, stats }) => - (currentWN8 === undefined ? 0 : stats.all.battles) + accumulator, - 0, - ); - const currentWN8 = - diff.list.reduce( - (accumulator, { currentWN8, stats }) => - stats.all.battles * (currentWN8 ?? 0) + accumulator, - 0, - ) / battlesWithWN8!; - - return { - title: 'WN8', - current: battlesWithWN8 - ? Math.round(currentWN8!).toLocaleString() - : '--', - percentile: battlesWithWN8 ? getWN8Percentile(currentWN8!) : undefined, - career: Math.round(diff.careerWN8).toLocaleString(), - }; - })(), - damage: { - title: 'Damage', - delta: sessionBattles === 0 ? 0 : currentDamage - careerDamage, - current: sessionBattles - ? Math.round(currentDamage).toLocaleString() - : '--', - career: Math.round(careerDamage).toLocaleString(), - }, - none: undefined, - }; - - return ( - - -
- - {session.showTotal && - session.isTracking && - since !== undefined && - diff !== undefined && ( - { - const rowStat = totalRowStats[customColumn.display]; - - if (!rowStat) return undefined; - - return { - ...rowStat, - delta: - customColumn.showDelta && - rowStat.percentile === undefined - ? rowStat.delta - : undefined, - }; - })} - /> - )} - - {diff?.list - .sort( - (a, b) => b.stats.last_battle_time - a.stats.last_battle_time, - ) - .map( - ({ stats, tankDefinitions, career, careerWN8, currentWN8 }) => { - const rowStats: Record< - CustomColumnDisplay, - Breakdown.RowStatItem | undefined - > = { - battles: { - title: 'Battles', - current: stats.all.battles.toLocaleString(), - career: career.all.battles.toLocaleString(), - }, - winrate: { - title: 'Winrate', - current: `${( - 100 * - (stats.all.wins / stats.all.battles) - ).toFixed(2)}%`, - career: `${( - 100 * - (career.all.wins / career.all.battles) - ).toFixed(2)}%`, - delta: - stats.all.wins / stats.all.battles - - career.all.wins / career.all.battles, - }, - wn8: { - title: 'WN8', - current: - currentWN8 === undefined - ? undefined - : Math.round(currentWN8).toLocaleString(), - career: - careerWN8 === undefined - ? undefined - : Math.round(careerWN8).toLocaleString(), - percentile: - currentWN8 === undefined - ? undefined - : getWN8Percentile(currentWN8), - }, - damage: { - title: 'Damage', - current: Math.round( - stats.all.damage_dealt / stats.all.battles, - ).toLocaleString(), - career: Math.round( - career.all.damage_dealt / career.all.battles, - ).toLocaleString(), - delta: - stats.all.damage_dealt / stats.all.battles - - career.all.damage_dealt / career.all.battles, - }, - none: undefined, - }; - - return ( - { - const rowStat = rowStats[customColumn.display]; - - if (!rowStat) return undefined; - - return { - ...rowStat, - delta: - customColumn.showDelta && - rowStat.percentile === undefined - ? rowStat.delta - : undefined, - }; - })} - /> - ); - }, - )} - -
-
- - - - ); -} diff --git a/src/app/tools/session/page.tsx b/src/app/tools/session/page.tsx index 2217532d1..6d6aea4ce 100644 --- a/src/app/tools/session/page.tsx +++ b/src/app/tools/session/page.tsx @@ -38,6 +38,7 @@ import searchPlayersAcrossRegions, { import { tankDefinitions } from '../../../core/blitzkit/tankDefinitions'; import { tankIcon } from '../../../core/blitzkit/tankIcon'; import { tankAverages } from '../../../core/blitzstars/tankAverages'; +import { deltaTankStats } from '../../../core/statistics/deltaTankStats'; import { theme } from '../../../stitches.config'; import { useApp } from '../../../stores/app'; import mutateSession, { @@ -71,6 +72,15 @@ export default function Page() { [session.tracking && session.player.id], ); const accountInfo = use(accountInfoPromise); + const delta = useMemo( + () => + session.tracking && tankStatsB + ? deltaTankStats(session.player.stats, tankStatsB).sort( + (a, b) => b.last_battle_time - a.last_battle_time, + ) + : undefined, + [session.tracking && session.player, tankStatsB], + ); const search = debounce(async () => { if (!input.current) return; @@ -248,7 +258,12 @@ export default function Page() {