From ba84f902216d8e1ad296ce8a32a9033512d7e38e Mon Sep 17 00:00:00 2001 From: Taken Date: Sun, 24 Aug 2025 13:48:40 +0200 Subject: [PATCH] feat(skywars): add full mode stats rows and best mode detection --- .../player/[ign]/_stats/skywars/table.tsx | 142 ++++++++++++++++++ src/lib/hypixel/skywars.ts | 92 ++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 src/app/(stats)/player/[ign]/_stats/skywars/table.tsx diff --git a/src/app/(stats)/player/[ign]/_stats/skywars/table.tsx b/src/app/(stats)/player/[ign]/_stats/skywars/table.tsx new file mode 100644 index 0000000..c640b4e --- /dev/null +++ b/src/app/(stats)/player/[ign]/_stats/skywars/table.tsx @@ -0,0 +1,142 @@ +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" +import { formatNumber } from "@/lib/formatters" +import { _SkywarsStats, getBestMode, getSkywarsModeStats } from "@/lib/hypixel/skywars" +import { NonNullStats } from "@/lib/schema/player" +import { cn } from "@/lib/utils" + +export default function SkywarsStatTable({ stats }: { stats: NonNullStats["SkyWars"] }) { + return ( + + + + + + + + + + + +
+ ) +} + +function SkywarsTableHeader() { + const headerElements = [ + "Mode", + "Kills", + "Deaths", + "KD", + "Wins", + "Losses", + "WL" + ] + + return ( + + + {headerElements.map((v, i) => { + return {v} + })} + + + ) +} + +function Normal({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("normal", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "normal" + + return ( + + Solo Normal + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function Insane({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("insane", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "insane" + + return ( + + Solo Insane + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function TeamsNormal({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("teams_normal", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "teams_normal" + + return ( + + Teams Normal + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function TeamsInsane({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("teams_insane", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "teams_insane" + + return ( + + Teams Insane + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function Mega({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("mega", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "mega" + + return ( + + Mega + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function MegaDoubles({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("mega_doubles", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "mega_doubles" + + return ( + + Mega Doubles + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} + +function Ranked({ stats }: { stats: NonNullStats["SkyWars"] }) { + const modeStats = getSkywarsModeStats("ranked", stats as _SkywarsStats) + const isBest = getBestMode(stats as _SkywarsStats) === "ranked" + + return ( + + Ranked + {modeStats.map((v, i) => { + return {typeof v === "number" ? formatNumber(v) : v} + })} + + ) +} diff --git a/src/lib/hypixel/skywars.ts b/src/lib/hypixel/skywars.ts index cb5c979..9fcc520 100644 --- a/src/lib/hypixel/skywars.ts +++ b/src/lib/hypixel/skywars.ts @@ -1,5 +1,6 @@ import { ICONS, PRESTIGES } from "@/data/hypixel/skywars" import { floorLevel } from "./formatters" +import { devide } from "./general" export function getTextColor(level: number) { const floored = floorLevel(level, 5) @@ -36,3 +37,94 @@ export function getPrestigeName(level: number) { return PRESTIGES.find(p => p.level === floored)!.name } + +export type _SkywarsStats = Record +type Mode = + | "normal" + | "insane" + | "teams_normal" + | "teams_insane" + | "mega" + | "mega_doubles" + | "ranked" + +export type SkywarsModeStats = { + kills: number + deaths: number + wins: number + losses: number +} + +export function getBestMode(stats: _SkywarsStats): Mode | null { + const { wins: normal } = getSkywarsModeStats("normal", stats, true) + const { wins: insane } = getSkywarsModeStats("insane", stats, true) + const { wins: teams_normal } = getSkywarsModeStats("teams_normal", stats, true) + const { wins: teams_insane } = getSkywarsModeStats("teams_insane", stats, true) + const { wins: mega } = getSkywarsModeStats("mega", stats, true) + const { wins: mega_doubles } = getSkywarsModeStats("mega_doubles", stats, true) + const { wins: ranked } = getSkywarsModeStats("ranked", stats, true) + + const max = Math.max(normal, insane, teams_normal, teams_insane, mega, mega_doubles, ranked) + + switch (max) { + case normal: + return "normal" + case insane: + return "insane" + case teams_normal: + return "teams_normal" + case teams_insane: + return "teams_insane" + case mega: + return "mega" + case mega_doubles: + return "mega_doubles" + case ranked: + return "ranked" + default: + return null + } +} + +export function getSkywarsModeStats(mode: Mode, stats: _SkywarsStats, raw: true): SkywarsModeStats +export function getSkywarsModeStats(mode: Mode, stats: _SkywarsStats, raw?: false): (string | number)[] +export function getSkywarsModeStats(mode: Mode, stats: _SkywarsStats, raw = false) { + switch (mode) { + case "normal": + return skywarsModeStats("solo_normal", stats, raw) + case "insane": + return skywarsModeStats("solo_insane", stats, raw) + case "teams_normal": + return skywarsModeStats("team_normal", stats, raw) + case "teams_insane": + return skywarsModeStats("team_insane", stats, raw) + case "mega": + return skywarsModeStats("mega_mega", stats, raw) + case "mega_doubles": + return skywarsModeStats("mega_doubles", stats, raw) + case "ranked": + return skywarsModeStats("ranked_normal", stats, raw) + default: + throw new Error(`${mode satisfies never} does not exist`) + } +} + +function skywarsModeStats(suffix: string, stats: _SkywarsStats, raw = false) { + if (raw) { + return { + kills: stats[`kills_${suffix}`], + deaths: stats[`deaths_${suffix}`], + wins: stats[`wins_${suffix}`], + losses: stats[`losses_${suffix}`] + } + } + + return [ + stats[`kills_${suffix}`], + stats[`deaths_${suffix}`], + devide(stats[`kills_${suffix}`], stats[`deaths_${suffix}`]).toFixed(2), + stats[`wins_${suffix}`], + stats[`losses_${suffix}`], + devide(stats[`wins_${suffix}`], stats[`losses_${suffix}`]).toFixed(2) + ] +}