Added first table row

This commit is contained in:
2025-09-02 00:07:36 +02:00
parent c2a22471b6
commit f18c2dee3b
4 changed files with 250 additions and 251 deletions

View File

@@ -2,7 +2,7 @@ import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/
import { Card, CardContent } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
import { formatNumber } from "@/lib/formatters"
import { getDivision, getMostPlayed } from "@/lib/hypixel/duels/duels"
import { getAllDivisions, getMostPlayed } from "@/lib/hypixel/duels/duels"
import { romanize } from "@/lib/hypixel/general"
import { NonNullStats } from "@/lib/schema/player"
import CollapsedStats from "../../_components/CollapsedStats"
@@ -14,7 +14,7 @@ export default function DuelsStats({ stats }: { stats: NonNullStats["Duels"] })
const wl = stats.wins / stats.losses
const kd = stats.kills / stats.deaths
const div = getDivision("all_modes", stats)
const div = getAllDivisions(stats)
const mostPlayed = getMostPlayed(stats)
return (

View File

@@ -1,10 +1,15 @@
import { Table, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { formatNumber } from "@/lib/formatters"
import { getDuelsModeStats, getModeTitle } from "@/lib/hypixel/duels/duels"
import { NonNullStats } from "@/lib/schema/player"
export default function DuelsStatTable({ stats }: { stats: NonNullStats["Duels"] }) {
return (
<Table>
<DuelsTableHeader />
<TableBody>
<UHC1v1Stats stats={stats} />
</TableBody>
</Table>
)
}
@@ -36,3 +41,20 @@ function DuelsTableHeader() {
</TableHeader>
)
}
function UHC1v1Stats({ stats }: { stats: NonNullStats["Duels"] }) {
if (!stats) return null
const modeStats = getDuelsModeStats("uhc_duel", stats)
const title = getModeTitle("uhc_duel")
return (
<TableRow>
<TableCell>{title}</TableCell>
<TableCell>I</TableCell>
{modeStats.map((v, i) => {
return <TableCell key={i}>{typeof v === "number" ? formatNumber(v) : v}</TableCell>
})}
</TableRow>
)
}

View File

@@ -1,16 +1,23 @@
import { DIVISIONS, MODES } from "@/data/hypixel/duels"
import { formatNumber } from "@/lib/formatters"
import { NonNullStats } from "@/lib/schema/player"
import { devide } from "../general"
type DuelType = "all_modes"
export type Div = {
name: typeof DIVISIONS[number]["name"]
level: number
color: typeof DIVISIONS[number]["color"]
}
export function getDivision(duelType: DuelType, stats: NonNullable<NonNullStats["Duels"]>) {
export function getModeTitle(id: typeof MODES[number]["id"]) {
const div = MODES.find(d => d.id === id)
return div!.name
}
export function getAllDivisions(stats: NonNullable<NonNullStats["Duels"]>) {
for (const div of DIVISIONS.slice().reverse()) {
const index = `${duelType}_${div.id}_title_prestige` as const
const index = `all_modes_${div.id}_title_prestige` as const
const val = stats[index]
if (val > 0) {
return {
@@ -36,3 +43,46 @@ export function getMostPlayed(stats: NonNullable<NonNullStats["Duels"]>) {
}
return mostPlayed
}
type Mode = typeof MODES[number]["id"]
// export function getBestMode(stats: NonNullable<NonNullStats["Duels"]>) {
// const { wins_bedwars: solo } = getBedwarsModeStats("solo", stats, true)
// const { wins_bedwars: doubles } = getBedwarsModeStats("doubles", stats, true)
// const { wins_bedwars: threes } = getBedwarsModeStats("3s", stats, true)
// const { wins_bedwars: fours } = getBedwarsModeStats("4s", stats, true)
//
// const max = Math.max(solo, doubles, threes, fours)
//
// switch (max) {
// case solo:
// return "solo"
// case doubles:
// return "doubles"
// case threes:
// return "3s"
// case fours:
// return "4s"
// default:
// return null
// }
// }
export function getDuelsModeStats(mode: Mode, stats: NonNullable<NonNullStats["Duels"]>) {
return duelsModeStats(mode, stats)
}
function duelsModeStats(index: typeof MODES[number]["id"], stats: NonNullable<NonNullStats["Duels"]>) {
return [
stats[`${index}_kills`],
stats[`${index}_deaths`],
formatNumber(devide(stats[`${index}_kills`], stats[`${index}_deaths`])),
stats[`${index}_wins`],
stats[`${index}_losses`],
formatNumber(devide(stats[`${index}_wins`], stats[`${index}_losses`])),
stats[`current_winstreak_mode_${index}`] ?? -1,
stats[`best_winstreak_mode_${index}`] ?? -1,
formatNumber(devide(stats[`${index}_melee_hits`], stats[`${index}_melee_swings`])),
formatNumber(devide(stats[`${index}_bow_hits`], stats[`${index}_bow_shots`]))
]
}

View File

@@ -1,5 +1,61 @@
import z from "zod"
function bedwarsModeStats() {
const ids = [
"eight_one",
"eight_two",
"four_three",
"four_four",
"two_four",
"eight_two_rush",
"four_four_rush",
"eight_two_ultimate",
"four_four_ultimate",
"eight_two_lucky",
"four_four_lucky",
"eight_two_voidless",
"four_four_voidless",
"eight_two_armed",
"four_four_armed",
"four_four_swap",
"four_four_underworld",
"castle"
] as const
const stats = [
"winstreak",
"kills_bedwars",
"deaths_bedwars",
"final_kills_bedwars",
"final_deaths_bedwars",
"wins_bedwars",
"losses_bedwars",
"beds_broken_bedwars",
"beds_lost_bedwars"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
const winstreak = new Map<string, z.ZodOptional<z.ZodNumber>>()
for (const id of ids) {
for (const stat of stats) {
if (stat === "winstreak") {
winstreak.set(`${id}_${stat}`, z.number().optional())
} else {
entries.set(`${id}_${stat}`, z.number().default(0))
}
}
}
type Modes = typeof ids[number]
type Stats = Exclude<typeof stats[number], "winstreak">
return {
all: Object.fromEntries(entries) as Record<`${Modes}_${Stats}`, z.ZodDefault<z.ZodNumber>>,
winstreak: Object.fromEntries(winstreak) as Record<`${Modes}_winstreak`, z.ZodOptional<z.ZodNumber>>
}
}
export const bedwarsStatsSchema = z.looseObject({
Experience: z.number().default(0),
coins: z.number().default(0),
@@ -25,170 +81,39 @@ export const bedwarsStatsSchema = z.looseObject({
doublers: z.number().default(0),
room: z.record(z.string(), z.boolean()).optional()
}).optional(),
eight_one_winstreak: z.number().optional(),
eight_one_kills_bedwars: z.number().default(0),
eight_one_deaths_bedwars: z.number().default(0),
eight_one_final_kills_bedwars: z.number().default(0),
eight_one_final_deaths_bedwars: z.number().default(0),
eight_one_wins_bedwars: z.number().default(0),
eight_one_losses_bedwars: z.number().default(0),
eight_one_beds_broken_bedwars: z.number().default(0),
eight_one_beds_lost_bedwars: z.number().default(0),
eight_two_winstreak: z.number().optional(),
eight_two_kills_bedwars: z.number().default(0),
eight_two_deaths_bedwars: z.number().default(0),
eight_two_final_kills_bedwars: z.number().default(0),
eight_two_final_deaths_bedwars: z.number().default(0),
eight_two_wins_bedwars: z.number().default(0),
eight_two_losses_bedwars: z.number().default(0),
eight_two_beds_broken_bedwars: z.number().default(0),
eight_two_beds_lost_bedwars: z.number().default(0),
four_three_winstreak: z.number().optional(),
four_three_kills_bedwars: z.number().default(0),
four_three_deaths_bedwars: z.number().default(0),
four_three_final_kills_bedwars: z.number().default(0),
four_three_final_deaths_bedwars: z.number().default(0),
four_three_wins_bedwars: z.number().default(0),
four_three_losses_bedwars: z.number().default(0),
four_three_beds_broken_bedwars: z.number().default(0),
four_three_beds_lost_bedwars: z.number().default(0),
four_four_winstreak: z.number().optional(),
four_four_kills_bedwars: z.number().default(0),
four_four_deaths_bedwars: z.number().default(0),
four_four_final_kills_bedwars: z.number().default(0),
four_four_final_deaths_bedwars: z.number().default(0),
four_four_wins_bedwars: z.number().default(0),
four_four_losses_bedwars: z.number().default(0),
four_four_beds_broken_bedwars: z.number().default(0),
four_four_beds_lost_bedwars: z.number().default(0),
two_four_winstreak: z.number().optional(),
two_four_kills_bedwars: z.number().default(0),
two_four_deaths_bedwars: z.number().default(0),
two_four_final_kills_bedwars: z.number().default(0),
two_four_final_deaths_bedwars: z.number().default(0),
two_four_wins_bedwars: z.number().default(0),
two_four_losses_bedwars: z.number().default(0),
two_four_beds_broken_bedwars: z.number().default(0),
two_four_beds_lost_bedwars: z.number().default(0),
eight_two_rush_winstreak: z.number().optional(),
eight_two_rush_kills_bedwars: z.number().default(0),
eight_two_rush_deaths_bedwars: z.number().default(0),
eight_two_rush_final_kills_bedwars: z.number().default(0),
eight_two_rush_final_deaths_bedwars: z.number().default(0),
eight_two_rush_wins_bedwars: z.number().default(0),
eight_two_rush_losses_bedwars: z.number().default(0),
eight_two_rush_beds_broken_bedwars: z.number().default(0),
eight_two_rush_beds_lost_bedwars: z.number().default(0),
four_four_rush_winstreak: z.number().optional(),
four_four_rush_kills_bedwars: z.number().default(0),
four_four_rush_deaths_bedwars: z.number().default(0),
four_four_rush_final_kills_bedwars: z.number().default(0),
four_four_rush_final_deaths_bedwars: z.number().default(0),
four_four_rush_wins_bedwars: z.number().default(0),
four_four_rush_losses_bedwars: z.number().default(0),
four_four_rush_beds_broken_bedwars: z.number().default(0),
four_four_rush_beds_lost_bedwars: z.number().default(0),
eight_two_ultimate_winstreak: z.number().optional(),
eight_two_ultimate_kills_bedwars: z.number().default(0),
eight_two_ultimate_deaths_bedwars: z.number().default(0),
eight_two_ultimate_final_kills_bedwars: z.number().default(0),
eight_two_ultimate_final_deaths_bedwars: z.number().default(0),
eight_two_ultimate_wins_bedwars: z.number().default(0),
eight_two_ultimate_losses_bedwars: z.number().default(0),
eight_two_ultimate_beds_broken_bedwars: z.number().default(0),
eight_two_ultimate_beds_lost_bedwars: z.number().default(0),
four_four_ultimate_winstreak: z.number().optional(),
four_four_ultimate_kills_bedwars: z.number().default(0),
four_four_ultimate_deaths_bedwars: z.number().default(0),
four_four_ultimate_final_kills_bedwars: z.number().default(0),
four_four_ultimate_final_deaths_bedwars: z.number().default(0),
four_four_ultimate_wins_bedwars: z.number().default(0),
four_four_ultimate_losses_bedwars: z.number().default(0),
four_four_ultimate_beds_broken_bedwars: z.number().default(0),
four_four_ultimate_beds_lost_bedwars: z.number().default(0),
eight_two_lucky_winstreak: z.number().optional(),
eight_two_lucky_kills_bedwars: z.number().default(0),
eight_two_lucky_deaths_bedwars: z.number().default(0),
eight_two_lucky_final_kills_bedwars: z.number().default(0),
eight_two_lucky_final_deaths_bedwars: z.number().default(0),
eight_two_lucky_wins_bedwars: z.number().default(0),
eight_two_lucky_losses_bedwars: z.number().default(0),
eight_two_lucky_beds_broken_bedwars: z.number().default(0),
eight_two_lucky_beds_lost_bedwars: z.number().default(0),
four_four_lucky_winstreak: z.number().optional(),
four_four_lucky_kills_bedwars: z.number().default(0),
four_four_lucky_deaths_bedwars: z.number().default(0),
four_four_lucky_final_kills_bedwars: z.number().default(0),
four_four_lucky_final_deaths_bedwars: z.number().default(0),
four_four_lucky_wins_bedwars: z.number().default(0),
four_four_lucky_losses_bedwars: z.number().default(0),
four_four_lucky_beds_broken_bedwars: z.number().default(0),
four_four_lucky_beds_lost_bedwars: z.number().default(0),
eight_two_voidless_winstreak: z.number().optional(),
eight_two_voidless_kills_bedwars: z.number().default(0),
eight_two_voidless_deaths_bedwars: z.number().default(0),
eight_two_voidless_final_kills_bedwars: z.number().default(0),
eight_two_voidless_final_deaths_bedwars: z.number().default(0),
eight_two_voidless_wins_bedwars: z.number().default(0),
eight_two_voidless_losses_bedwars: z.number().default(0),
eight_two_voidless_beds_broken_bedwars: z.number().default(0),
eight_two_voidless_beds_lost_bedwars: z.number().default(0),
four_four_voidless_winstreak: z.number().optional(),
four_four_voidless_kills_bedwars: z.number().default(0),
four_four_voidless_deaths_bedwars: z.number().default(0),
four_four_voidless_final_kills_bedwars: z.number().default(0),
four_four_voidless_final_deaths_bedwars: z.number().default(0),
four_four_voidless_wins_bedwars: z.number().default(0),
four_four_voidless_losses_bedwars: z.number().default(0),
four_four_voidless_beds_broken_bedwars: z.number().default(0),
four_four_voidless_beds_lost_bedwars: z.number().default(0),
eight_two_armed_winstreak: z.number().optional(),
eight_two_armed_kills_bedwars: z.number().default(0),
eight_two_armed_deaths_bedwars: z.number().default(0),
eight_two_armed_final_kills_bedwars: z.number().default(0),
eight_two_armed_final_deaths_bedwars: z.number().default(0),
eight_two_armed_wins_bedwars: z.number().default(0),
eight_two_armed_losses_bedwars: z.number().default(0),
eight_two_armed_beds_broken_bedwars: z.number().default(0),
eight_two_armed_beds_lost_bedwars: z.number().default(0),
four_four_armed_winstreak: z.number().optional(),
four_four_armed_kills_bedwars: z.number().default(0),
four_four_armed_deaths_bedwars: z.number().default(0),
four_four_armed_final_kills_bedwars: z.number().default(0),
four_four_armed_final_deaths_bedwars: z.number().default(0),
four_four_armed_wins_bedwars: z.number().default(0),
four_four_armed_losses_bedwars: z.number().default(0),
four_four_armed_beds_broken_bedwars: z.number().default(0),
four_four_armed_beds_lost_bedwars: z.number().default(0),
four_four_swap_winstreak: z.number().optional(),
four_four_swap_kills_bedwars: z.number().default(0),
four_four_swap_deaths_bedwars: z.number().default(0),
four_four_swap_final_kills_bedwars: z.number().default(0),
four_four_swap_final_deaths_bedwars: z.number().default(0),
four_four_swap_wins_bedwars: z.number().default(0),
four_four_swap_losses_bedwars: z.number().default(0),
four_four_swap_beds_broken_bedwars: z.number().default(0),
four_four_swap_beds_lost_bedwars: z.number().default(0),
four_four_underworld_winstreak: z.number().optional(),
four_four_underworld_kills_bedwars: z.number().default(0),
four_four_underworld_deaths_bedwars: z.number().default(0),
four_four_underworld_final_kills_bedwars: z.number().default(0),
four_four_underworld_final_deaths_bedwars: z.number().default(0),
four_four_underworld_wins_bedwars: z.number().default(0),
four_four_underworld_losses_bedwars: z.number().default(0),
four_four_underworld_beds_broken_bedwars: z.number().default(0),
four_four_underworld_beds_lost_bedwars: z.number().default(0),
castle_winstreak: z.number().optional(),
castle_kills_bedwars: z.number().default(0),
castle_deaths_bedwars: z.number().default(0),
castle_final_kills_bedwars: z.number().default(0),
castle_final_deaths_bedwars: z.number().default(0),
castle_wins_bedwars: z.number().default(0),
castle_losses_bedwars: z.number().default(0),
castle_beds_broken_bedwars: z.number().default(0),
castle_beds_lost_bedwars: z.number().default(0)
...bedwarsModeStats().all,
...bedwarsModeStats().winstreak
})
function skywarsModeStats() {
const ids = [
"solo_normal",
"solo_insane",
"team_normal",
"team_insane",
"mega",
"mega_doubles",
"ranked_normal"
] as const
const stats = [
"kills",
"deaths",
"wins",
"losses"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
for (const id of ids) {
for (const stat of stats) {
entries.set(`${stat}_${id}`, z.number().default(0))
}
}
return Object.fromEntries(entries) as Record<`${typeof stats[number]}_${typeof ids[number]}`, z.ZodDefault<z.ZodNumber>>
}
export const skywarsStatsSchema = z.looseObject({
skywars_experience: z.number().default(0),
selected_prestige_icon: z.string().optional(),
@@ -219,34 +144,6 @@ export const skywarsStatsSchema = z.looseObject({
paid_souls: z.number().default(0),
soul_well: z.number().default(0),
packages: z.array(z.string()),
kills_solo_normal: z.number().default(0),
deaths_solo_normal: z.number().default(0),
wins_solo_normal: z.number().default(0),
losses_solo_normal: z.number().default(0),
kills_solo_insane: z.number().default(0),
deaths_solo_insane: z.number().default(0),
wins_solo_insane: z.number().default(0),
losses_solo_insane: z.number().default(0),
kills_team_normal: z.number().default(0),
deaths_team_normal: z.number().default(0),
wins_team_normal: z.number().default(0),
losses_team_normal: z.number().default(0),
kills_team_insane: z.number().default(0),
deaths_team_insane: z.number().default(0),
wins_team_insane: z.number().default(0),
losses_team_insane: z.number().default(0),
kills_mega: z.number().default(0),
deaths_mega: z.number().default(0),
wins_mega: z.number().default(0),
losses_mega: z.number().default(0),
kills_mega_doubles: z.number().default(0),
deaths_mega_doubles: z.number().default(0),
wins_mega_doubles: z.number().default(0),
losses_mega_doubles: z.number().default(0),
kills_ranked_normal: z.number().default(0),
deaths_ranked_normal: z.number().default(0),
wins_ranked_normal: z.number().default(0),
losses_ranked_normal: z.number().default(0),
shard: z.number().default(0),
opals: z.number().default(0),
heads_eww: z.number().default(0),
@@ -266,9 +163,89 @@ export const skywarsStatsSchema = z.looseObject({
mode: z.string(),
sacrifice: z.string()
}))
}).optional()
}).optional(),
...skywarsModeStats()
})
function duelsModeStats() {
const ids = [
"uhc_duel",
"uhc_doubles",
"uhc_four",
"uhc_meetup",
"op_duel",
"op_doubles",
"sw_duel",
"sw_doubles",
"bow_duel",
"blitz_duel",
"mw_duel",
"mw_doubles",
"sumo_duel",
"bowspleef_duel",
"parkour_eight",
"boxing_duel",
"classic_duel",
"potion_duel",
"combo_duel",
"bridge_duel",
"bridge_doubles",
"bridge_threes",
"bridge_four",
"bridge_2v2v2v2",
"bridge_3v3v3v3",
"capture_threes",
"duel_arena"
] as const
const stats = [
"kills",
"deaths",
"wins",
"losses",
"melee_swings",
"melee_hits",
"bow_shots",
"bow_hits",
"current_winstreak_mode",
"best_winstreak_mode",
"goals"
] as const
const entries = new Map<string, z.ZodDefault<z.ZodNumber>>()
const ws = new Map<string, z.ZodOptional<z.ZodNumber>>()
const bestWs = new Map<string, z.ZodOptional<z.ZodNumber>>()
const bridge = new Map<string, z.ZodDefault<z.ZodNumber>>()
for (const id of ids) {
for (const stat of stats) {
if (id.startsWith("bridge_") && stat === "goals") {
bridge.set(`${id}_${stat}`, z.number().default(0))
continue
}
if (stat === "current_winstreak_mode") {
ws.set(`${stat}_${id}`, z.number().optional())
} else if (stat === "best_winstreak_mode") {
bestWs.set(`${stat}_${id}`, z.number().optional())
} else {
entries.set(`${id}_${stat}`, z.number().default(0))
}
}
}
type Modes = typeof ids[number]
type Stats = Exclude<typeof stats[number], "current_winstreak_mode" | "best_winstreak_mode" | "goals">
type BridgeModes = Extract<Modes, "bridge_duel" | "bridge_doubles" | "bridge_threes" | "bridge_four" | "bridge_2v2v2v2" | "bridge_3v3v3v3">
return {
all: Object.fromEntries(entries) as Record<`${Modes}_${Stats}`, z.ZodDefault<z.ZodNumber>>,
ws: Object.fromEntries(ws) as Record<`current_winstreak_mode_${Modes}`, z.ZodOptional<z.ZodNumber>>,
bestWs: Object.fromEntries(bestWs) as Record<`best_winstreak_mode_${Modes}`, z.ZodOptional<z.ZodNumber>>,
bridge: Object.fromEntries(bridge) as Record<`${BridgeModes}_goals`, z.ZodDefault<z.ZodNumber>>
}
}
export const duelsStatsSchema = z.looseObject({
wins: z.number().default(0),
losses: z.number().default(0),
@@ -293,58 +270,8 @@ export const duelsStatsSchema = z.looseObject({
all_modes_celestial_title_prestige: z.number().default(-1),
all_modes_divine_title_prestige: z.number().default(-1),
all_modes_ascended_title_prestige: z.number().default(-1),
uhc_duel_wins: z.number().default(0),
uhc_doubles_wins: z.number().default(0),
uhc_four_wins: z.number().default(0),
uhc_meetup_wins: z.number().default(0),
op_duel_wins: z.number().default(0),
op_doubles_wins: z.number().default(0),
sw_duel_wins: z.number().default(0),
sw_doubles_wins: z.number().default(0),
bow_duel_wins: z.number().default(0),
blitz_duel_wins: z.number().default(0),
mw_duel_wins: z.number().default(0),
mw_doubles_wins: z.number().default(0),
sumo_duel_wins: z.number().default(0),
bowspleef_duel_wins: z.number().default(0),
parkour_eight_wins: z.number().default(0),
boxing_duel_wins: z.number().default(0),
classic_duel_wins: z.number().default(0),
potion_duel_wins: z.number().default(0),
combo_duel_wins: z.number().default(0),
bridge_duel_wins: z.number().default(0),
bridge_doubles_wins: z.number().default(0),
bridge_threes_wins: z.number().default(0),
bridge_four_wins: z.number().default(0),
bridge_2v2v2v2_wins: z.number().default(0),
bridge_3v3v3v3_wins: z.number().default(0),
capture_threes_wins: z.number().default(0),
duel_arena_wins: z.number().default(0),
uhc_duel_losses: z.number().default(0),
uhc_doubles_losses: z.number().default(0),
uhc_four_losses: z.number().default(0),
uhc_meetup_losses: z.number().default(0),
op_duel_losses: z.number().default(0),
op_doubles_losses: z.number().default(0),
sw_duel_losses: z.number().default(0),
sw_doubles_losses: z.number().default(0),
bow_duel_losses: z.number().default(0),
blitz_duel_losses: z.number().default(0),
mw_duel_losses: z.number().default(0),
mw_doubles_losses: z.number().default(0),
sumo_duel_losses: z.number().default(0),
bowspleef_duel_losses: z.number().default(0),
parkour_eight_losses: z.number().default(0),
boxing_duel_losses: z.number().default(0),
classic_duel_losses: z.number().default(0),
potion_duel_losses: z.number().default(0),
combo_duel_losses: z.number().default(0),
bridge_duel_losses: z.number().default(0),
bridge_doubles_losses: z.number().default(0),
bridge_threes_losses: z.number().default(0),
bridge_four_losses: z.number().default(0),
bridge_2v2v2v2_losses: z.number().default(0),
bridge_3v3v3v3_losses: z.number().default(0),
capture_threes_losses: z.number().default(0),
duel_arena_losses: z.number().default(0)
...duelsModeStats().all,
...duelsModeStats().ws,
...duelsModeStats().bestWs,
...duelsModeStats().bridge
})