feat: variable player count

This commit is contained in:
TrèsAbhi committed 2024-07-12 13:53:11 -05:00
1 parent d6fc037d4f
commit 03ce75c15d
15 files changed
+149 -28

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
# BlitzKit 1.21.0
Introducing the Tank performance tool!
![](https://i.imgur.com/1TZzVnp.png)
## Features
- Added the Tank performance tool
- The tankopedia search page now loads much faster
- Not all tanks are loaded at once; rather, more tanks are loaded as you scroll down the page
## Fixes
- The footer is now better centered
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "blitzkit",
"version": "1.20.5",
"version": "1.21.0",
"description": "🎉 Tools for everything World of Tanks Blitz",
"main": "src/server.ts",
"type": "module",
+1 -1
View File
@@ -1 +1 @@
["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"]
["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.21.0","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"]
@@ -0,0 +1,11 @@
import { FilterControl } from '../../tankopedia/components/FilterControl';
import { PlayerCountControl } from './PlayerCountControl';
export function Controls() {
return (
<>
<FilterControl />
<PlayerCountControl />
</>
);
}
@@ -9,8 +9,8 @@ import { Flex, IconButton, Table } from '@radix-ui/themes';
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
import * as TankPerformanceSort from '../../../../stores/tankPerformanceSort';
import {
tankPerformanceSortTypeNames,
tankPerformanceSortTypeNamesArray,
TankPerformanceSortTypeNames,
TankPerformanceSortTypeNamesArray,
} from '../../../../stores/tankPerformanceSort/constants';
export function Header() {
@@ -21,7 +21,7 @@ export function Header() {
<Table.Header>
<Table.Row align="center">
<StickyColumnHeaderCell>Tank</StickyColumnHeaderCell>
{tankPerformanceSortTypeNamesArray.map((type) => {
{TankPerformanceSortTypeNamesArray.map((type) => {
const isSelected = sort.type === type;
return (
@@ -32,7 +32,7 @@ export function Header() {
justify="center"
>
<Flex align="center" gap="1">
{tankPerformanceSortTypeNames[type]}
{TankPerformanceSortTypeNames[type]}
<IconButton
size={isSelected ? '1' : '2'}
@@ -0,0 +1,48 @@
'use client';
import { Flex, Select, Text } from '@radix-ui/themes';
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
import { PlayerCountPeriod } from '../../../../stores/tankPerformancePersistent/constants';
export function PlayerCountControl() {
const playerCountPeriod = TankPerformancePersistent.use(
(state) => state.playerCountPeriod,
);
const mutateTankPerformanceSort = TankPerformancePersistent.useMutation();
return (
<Flex justify="center" align="center" gap="2">
<Text>Player count</Text>
<Select.Root
value={playerCountPeriod}
onValueChange={(period) => {
mutateTankPerformanceSort((draft) => {
draft.playerCountPeriod = period as PlayerCountPeriod;
});
}}
>
<Select.Trigger />
<Select.Content>
<Select.Item value={PlayerCountPeriod.Past120Days}>
Past 120 days
</Select.Item>
<Select.Item value={PlayerCountPeriod.Past90Days}>
Past 90 days
</Select.Item>
<Select.Item value={PlayerCountPeriod.Past60Days}>
Past 60 days
</Select.Item>
<Select.Item value={PlayerCountPeriod.ThisMonth}>
This month
</Select.Item>
<Select.Item value={PlayerCountPeriod.ThisWeek}>
This week
</Select.Item>
<Select.Item value={PlayerCountPeriod.Yesterday}>
Yesterday
</Select.Item>
</Select.Content>
</Select.Root>
</Flex>
);
}
@@ -2,7 +2,7 @@ import { Skeleton, Table } from '@radix-ui/themes';
import { times } from 'lodash';
import { memo, useRef } from 'react';
import { useIntersection } from '../../../../hooks/useIntersection';
import { tankPerformanceSortTypeNamesArray } from '../../../../stores/tankPerformanceSort/constants';
import { TankPerformanceSortTypeNamesArray } from '../../../../stores/tankPerformanceSort/constants';
interface RowLoaderProps {
onIntersection?: () => void;
@@ -21,7 +21,7 @@ export const RowLoader = memo<RowLoaderProps>(({ onIntersection }) => {
<Skeleton height="100%" width="128px" />
</Table.RowHeaderCell>
{times(tankPerformanceSortTypeNamesArray.length, (index) => (
{times(TankPerformanceSortTypeNamesArray.length, (index) => (
<Table.Cell key={index} align="center">
<Skeleton height="1em" width="32px" />
</Table.Cell>
@@ -5,6 +5,7 @@ import { averageDefinitions } from '../../../../core/blitzkit/averageDefinitions
import { TankDefinition } from '../../../../core/blitzkit/tankDefinitions';
import { formatCompact } from '../../../../core/math/formatCompact';
import { useAveragesExclusionRatio } from '../../../../hooks/useAveragesExclusionRatio';
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
interface TankRowProps {
tank: TankDefinition;
@@ -15,6 +16,9 @@ export const TankRow = memo<TankRowProps>(
const awaitedAverageDefinitions = use(averageDefinitions);
const averages = awaitedAverageDefinitions.averages[tank.id];
const ratio = useAveragesExclusionRatio();
const playerCountPeriod = TankPerformancePersistent.use(
(state) => state.playerCountPeriod,
);
return (
<Table.Row>
@@ -24,7 +28,9 @@ export const TankRow = memo<TankRowProps>(
{((averages.mu.wins / averages.mu.battles) * 100).toFixed(1)}%
</Table.Cell>
<Table.Cell align="center">
{formatCompact(Math.round(ratio * averages.samples.d_30))}
{formatCompact(
Math.round(ratio * averages.samples[playerCountPeriod]),
)}
</Table.Cell>
<Table.Cell align="center">
{formatCompact(
@@ -1,12 +1,14 @@
import { Table } from '@radix-ui/themes';
import { memo, useCallback } from 'react';
import { memo, use, useCallback } from 'react';
import { StickyRowHeaderCell } from '../../../../components/StickyRowHeaderCell';
import {
averageDefinitions,
AverageDefinitionsAllStats,
AverageDefinitionsEntryWithId,
} from '../../../../core/blitzkit/averageDefinitions';
import { formatCompact } from '../../../../core/math/formatCompact';
import { useAveragesExclusionRatio } from '../../../../hooks/useAveragesExclusionRatio';
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
interface TotalProps {
tanks: AverageDefinitionsEntryWithId[];
@@ -14,6 +16,10 @@ interface TotalProps {
export const Total = memo<TotalProps>(
({ tanks }) => {
const awaitedAverageDefinitions = use(averageDefinitions);
const playerCountPeriod = TankPerformancePersistent.use(
(state) => state.playerCountPeriod,
);
const ratio = useAveragesExclusionRatio();
const sum = useCallback(
(slice: (tank: AverageDefinitionsAllStats) => number) => {
@@ -25,7 +31,6 @@ export const Total = memo<TotalProps>(
[tanks],
);
const players = sum(() => 1);
const battles = sum(({ battles }) => battles);
const winrate = sum(({ wins }) => wins) / battles;
const damage = sum(({ damage_dealt }) => damage_dealt) / battles;
@@ -43,14 +48,15 @@ export const Total = memo<TotalProps>(
return (
<Table.Row>
<StickyRowHeaderCell
// maxWidth={{ initial: '128px', sm: '240px' }}
style={{ overflow: 'hidden', display: 'flex' }}
>
<StickyRowHeaderCell style={{ overflow: 'hidden', display: 'flex' }}>
Total
</StickyRowHeaderCell>
<Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell>
<Table.Cell align="center">{formatCompact(ratio * players)}</Table.Cell>
<Table.Cell align="center">
{formatCompact(
ratio * awaitedAverageDefinitions.samples[playerCountPeriod],
)}
</Table.Cell>
<Table.Cell align="center">{formatCompact(ratio * battles)}</Table.Cell>
<Table.Cell align="center">
{Math.round(damage).toLocaleString()}
+6 -3
View File
@@ -1,11 +1,14 @@
import { ReactNode } from 'react';
import * as TankFilters from '../../../stores/tankFilters';
import * as TankPerformancePersistent from '../../../stores/tankPerformancePersistent';
import * as TankPerformanceSort from '../../../stores/tankPerformanceSort';
export default function Layout({ children }: { children: ReactNode }) {
return (
<TankPerformanceSort.Provider>
<TankFilters.Provider>{children}</TankFilters.Provider>
</TankPerformanceSort.Provider>
<TankPerformancePersistent.Provider>
<TankPerformanceSort.Provider>
<TankFilters.Provider>{children}</TankFilters.Provider>
</TankPerformanceSort.Provider>
</TankPerformancePersistent.Provider>
);
}
+2 -2
View File
@@ -1,5 +1,5 @@
import PageWrapper from '../../../components/PageWrapper';
import { FilterControl } from '../tankopedia/components/FilterControl';
import { Controls } from './components/Controls';
import { Info } from './components/Info';
import { TankTable } from './components/Table';
@@ -8,7 +8,7 @@ export default function Page() {
<PageWrapper color="jade" noMaxWidth>
<Info />
{/* <TierBreakdown /> */}
<FilterControl />
<Controls />
<TankTable />
</PageWrapper>
);
@@ -0,0 +1,8 @@
export enum PlayerCountPeriod {
Past120Days = 'd_120',
Past90Days = 'd_90',
Past60Days = 'd_60',
ThisMonth = 'd_30',
ThisWeek = 'd_7',
Yesterday = 'd_1',
}
@@ -0,0 +1,23 @@
'use client';
import { merge } from 'lodash';
import { create } from 'zustand';
import { persist, subscribeWithSelector } from 'zustand/middleware';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import { PlayerCountPeriod } from './constants';
export interface TankPerformancePersistent {
playerCountPeriod: PlayerCountPeriod;
}
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
() =>
create<TankPerformancePersistent>()(
persist(
subscribeWithSelector<TankPerformancePersistent>(() => ({
playerCountPeriod: PlayerCountPeriod.ThisMonth,
})),
{ name: 'tank-performance', merge: (a, b) => merge(b, a) },
),
),
);
+6 -5
View File
@@ -1,9 +1,9 @@
import { TankPerformanceSortType } from '.';
export const tankPerformanceSortTypeNames = {
export const TankPerformanceSortTypeNames = {
winrate: 'Winrate',
players: 'Players (30d)',
battles: 'Battles (career)',
players: 'Players',
battles: 'Battles (total)',
damage: 'Damage',
survival: 'Survival',
xp: 'XP',
@@ -16,6 +16,7 @@ export const tankPerformanceSortTypeNames = {
damageTaken: 'Dmg. taken',
capturePoints: 'Cap points',
} as const;
export const tankPerformanceSortTypeNamesArray = Object.keys(
tankPerformanceSortTypeNames,
export const TankPerformanceSortTypeNamesArray = Object.keys(
TankPerformanceSortTypeNames,
) as TankPerformanceSortType[];
+2 -2
View File
@@ -2,9 +2,9 @@
import { create } from 'zustand';
import { createNextSafeStore } from '../../core/zustand/createNextSafeStore';
import { tankPerformanceSortTypeNames } from './constants';
import { TankPerformanceSortTypeNames } from './constants';
export type TankPerformanceSortType = keyof typeof tankPerformanceSortTypeNames;
export type TankPerformanceSortType = keyof typeof TankPerformanceSortTypeNames;
export interface TankPerformanceSort {
type: TankPerformanceSortType;