fix: performance filters

This commit is contained in:
TrèsAbhi committed 2025-10-11 21:45:18 -05:00
1 parent 4ab03e56a2
commit a4e48a2feb
2 files changed
+65 -53

No files matched your search

@@ -1,9 +1,10 @@
import { Table } from "@radix-ui/themes"; import { Table } from "@radix-ui/themes";
import { times } from "lodash-es"; import { times } from "lodash-es";
import { Fragment, Suspense, useEffect, useMemo, useState } from "react"; import { Fragment, Suspense, useEffect, useMemo, useState } from "react";
import usePromise from "react-promise-suspense";
import { awaitableAverageDefinitions } from "../../core/awaitables/averageDefinitions"; import { awaitableAverageDefinitions } from "../../core/awaitables/averageDefinitions";
import { awaitableTankDefinitions } from "../../core/awaitables/tankDefinitions"; import { awaitableTankDefinitions } from "../../core/awaitables/tankDefinitions";
import { filterTank } from "../../core/blitzkit/filterTank"; import { filterTanks } from "../../core/blitzkit/filterTanks";
import { Performance } from "../../stores/performance"; import { Performance } from "../../stores/performance";
import { TankFilters } from "../../stores/tankFilters"; import { TankFilters } from "../../stores/tankFilters";
import { TankPerformanceSort } from "../../stores/tankPerformanceSort"; import { TankPerformanceSort } from "../../stores/tankPerformanceSort";
@@ -20,12 +21,7 @@ const [tankDefinitions, averageDefinitions] = await Promise.all([
awaitableAverageDefinitions, awaitableAverageDefinitions,
]); ]);
const averageDefinitionsArray = Object.entries(averageDefinitions.averages).map( const tankList = Object.values(tankDefinitions.tanks);
([id, average]) => ({
id: Number(id),
...average,
})
);
export function Tanks({ skeleton }: MaybeSkeletonComponentProps) { export function Tanks({ skeleton }: MaybeSkeletonComponentProps) {
if (skeleton) { if (skeleton) {
@@ -39,98 +35,109 @@ export function Tanks({ skeleton }: MaybeSkeletonComponentProps) {
} }
const sort = TankPerformanceSort.use(); const sort = TankPerformanceSort.use();
const filters = TankFilters.use();
const filteredTanks = usePromise(
() =>
filterTanks(filters, tankList).then((tanks) =>
tanks.filter(({ id }) => id in averageDefinitions.averages)
),
// react-promise-suspense has awful type annotations
[filters] as any
);
const tanksMapped = useMemo(
() =>
filteredTanks.map(({ id }) => ({
id,
...averageDefinitions.averages[id],
})),
[filters]
);
const tanksSorted = useMemo(() => { const tanksSorted = useMemo(() => {
const { playerCountPeriod } = Performance.state; const { playerCountPeriod } = Performance.state;
switch (sort.type) { switch (sort.type) {
case "accuracy": case "accuracy":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * (a.mu.hits / a.mu.shots - b.mu.hits / b.mu.shots) sort.direction * (a.mu.hits / a.mu.shots - b.mu.hits / b.mu.shots)
); );
case "capture_points": case "capture_points":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.capture_points / a.mu.battles - (a.mu.capture_points / a.mu.battles -
b.mu.capture_points / b.mu.battles) b.mu.capture_points / b.mu.battles)
); );
case "damage": case "damage":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.damage_dealt / a.mu.battles - (a.mu.damage_dealt / a.mu.battles -
b.mu.damage_dealt / b.mu.battles) b.mu.damage_dealt / b.mu.battles)
); );
case "damage_ratio": case "damage_ratio":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.damage_dealt / a.mu.damage_received - (a.mu.damage_dealt / a.mu.damage_received -
b.mu.damage_dealt / b.mu.damage_received) b.mu.damage_dealt / b.mu.damage_received)
); );
case "damage_taken": case "damage_taken":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.damage_received / a.mu.battles - (a.mu.damage_received / a.mu.battles -
b.mu.damage_received / b.mu.battles) b.mu.damage_received / b.mu.battles)
); );
case "hits": case "hits":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.hits / a.mu.battles - b.mu.hits / b.mu.battles) (a.mu.hits / a.mu.battles - b.mu.hits / b.mu.battles)
); );
case "kills": case "kills":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.frags / a.mu.battles - b.mu.frags / b.mu.battles) (a.mu.frags / a.mu.battles - b.mu.frags / b.mu.battles)
); );
case "shots": case "shots":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.shots / a.mu.battles - b.mu.shots / b.mu.battles) (a.mu.shots / a.mu.battles - b.mu.shots / b.mu.battles)
); );
case "players": case "players":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.samples[playerCountPeriod] - b.samples[playerCountPeriod]) (a.samples[playerCountPeriod] - b.samples[playerCountPeriod])
); );
case "spots": case "spots":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.spotted / a.mu.battles - b.mu.spotted / b.mu.battles) (a.mu.spotted / a.mu.battles - b.mu.spotted / b.mu.battles)
); );
case "survival": case "survival":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.survived_battles / a.mu.battles - (a.mu.survived_battles / a.mu.battles -
b.mu.survived_battles / b.mu.battles) b.mu.survived_battles / b.mu.battles)
); );
case "winrate": case "winrate":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * sort.direction *
(a.mu.wins / a.mu.battles - b.mu.wins / b.mu.battles) (a.mu.wins / a.mu.battles - b.mu.wins / b.mu.battles)
); );
case "xp": case "xp":
return averageDefinitionsArray.sort( return tanksMapped.sort(
(a, b) => (a, b) =>
sort.direction * (a.mu.xp / a.mu.battles - b.mu.xp / b.mu.battles) sort.direction * (a.mu.xp / a.mu.battles - b.mu.xp / b.mu.battles)
); );
} }
}, [sort]);
const filters = TankFilters.use();
const tanks = useMemo(() => {
return tanksSorted.filter((tank) =>
filterTank(filters, tankDefinitions.tanks[tank.id])
);
}, [filters, sort]); }, [filters, sort]);
const [loadedRows, setLoadedRows] = useState(DEFAULT_LOADED_ROWS); const [loadedRows, setLoadedRows] = useState(DEFAULT_LOADED_ROWS);
@@ -140,9 +147,9 @@ export function Tanks({ skeleton }: MaybeSkeletonComponentProps) {
return ( return (
<Table.Body> <Table.Body>
<Total tanks={tanks} /> <Total tanks={tanksSorted} />
{tanks.slice(0, loadedRows).map((averages) => { {tanksSorted.slice(0, loadedRows).map((averages) => {
const tank = tankDefinitions.tanks[averages.id]; const tank = tankDefinitions.tanks[averages.id];
if (tank === undefined) return null; if (tank === undefined) return null;
@@ -156,16 +163,21 @@ export function Tanks({ skeleton }: MaybeSkeletonComponentProps) {
); );
})} })}
{times(Math.min(PREVIEW_COUNT, tanks.length - loadedRows), (index) => { {times(
return ( Math.min(PREVIEW_COUNT, tanksSorted.length - loadedRows),
<RowLoader (index) => {
key={index} return (
onIntersection={() => { <RowLoader
setLoadedRows((state) => Math.min(state + 2, tanks.length)); key={index}
}} onIntersection={() => {
/> setLoadedRows((state) =>
); Math.min(state + 2, tanksSorted.length)
})} );
}}
/>
);
}
)}
</Table.Body> </Table.Body>
); );
} }
@@ -2,16 +2,16 @@ import {
AverageDefinitionsEntry, AverageDefinitionsEntry,
formatCompact, formatCompact,
type BlitzkitStats, type BlitzkitStats,
} from '@blitzkit/core'; } from "@blitzkit/core";
import { Table } from '@radix-ui/themes'; import { Table } from "@radix-ui/themes";
import { memo, useCallback } from 'react'; import { memo, useCallback } from "react";
import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions'; import { awaitableAverageDefinitions } from "../../core/awaitables/averageDefinitions";
import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio'; import { useAveragesExclusionRatio } from "../../hooks/useAveragesExclusionRatio";
import { useLocale } from '../../hooks/useLocale'; import { useLocale } from "../../hooks/useLocale";
import { Performance } from '../../stores/performance'; import { Performance } from "../../stores/performance";
import { StickyRowHeaderCell } from '../StickyRowHeaderCell'; import { StickyRowHeaderCell } from "../StickyRowHeaderCell";
interface AverageDefinitionsEntryWithId extends AverageDefinitionsEntry { export interface AverageDefinitionsEntryWithId extends AverageDefinitionsEntry {
id: number; id: number;
} }
@@ -24,7 +24,7 @@ const averageDefinitions = await awaitableAverageDefinitions;
export const Total = memo<TotalProps>( export const Total = memo<TotalProps>(
({ tanks }) => { ({ tanks }) => {
const playerCountPeriod = Performance.use( const playerCountPeriod = Performance.use(
(state) => state.playerCountPeriod, (state) => state.playerCountPeriod
); );
const { strings, locale } = useLocale(); const { strings, locale } = useLocale();
const ratio = useAveragesExclusionRatio(); const ratio = useAveragesExclusionRatio();
@@ -32,10 +32,10 @@ export const Total = memo<TotalProps>(
(slice: (tank: BlitzkitStats) => number) => { (slice: (tank: BlitzkitStats) => number) => {
return tanks.reduce( return tanks.reduce(
(acc, tank) => acc + tank.samples[playerCountPeriod] * slice(tank.mu), (acc, tank) => acc + tank.samples[playerCountPeriod] * slice(tank.mu),
0, 0
); );
}, },
[tanks], [tanks]
); );
const battles = sum(({ battles }) => battles); const battles = sum(({ battles }) => battles);
@@ -55,14 +55,14 @@ export const Total = memo<TotalProps>(
return ( return (
<Table.Row> <Table.Row>
<StickyRowHeaderCell style={{ overflow: 'hidden', display: 'flex' }}> <StickyRowHeaderCell style={{ overflow: "hidden", display: "flex" }}>
{strings.website.tools.performance.table.tanks.total} {strings.website.tools.performance.table.tanks.total}
</StickyRowHeaderCell> </StickyRowHeaderCell>
<Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell> <Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell>
<Table.Cell align="center"> <Table.Cell align="center">
{formatCompact( {formatCompact(
locale, locale,
ratio * averageDefinitions.samples[playerCountPeriod], ratio * averageDefinitions.samples[playerCountPeriod]
)} )}
</Table.Cell> </Table.Cell>
<Table.Cell align="center"> <Table.Cell align="center">
@@ -87,5 +87,5 @@ export const Total = memo<TotalProps>(
</Table.Row> </Table.Row>
); );
}, },
(prev, next) => prev.tanks === next.tanks, (prev, next) => prev.tanks === next.tanks
); );