From 2b262025df87578c54590b85366deec3d891c2be Mon Sep 17 00:00:00 2001 From: Taken Date: Tue, 2 Sep 2025 13:57:52 +0200 Subject: [PATCH] Finished duels stats --- .../player/[ign]/_stats/duels/table.tsx | 15 +++-- src/data/hypixel/duels.ts | 10 ++-- src/lib/hypixel/duels/duels.ts | 28 +++++++-- src/lib/schema/stats.ts | 59 +++++++++++++++---- 4 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/app/(stats)/player/[ign]/_stats/duels/table.tsx b/src/app/(stats)/player/[ign]/_stats/duels/table.tsx index 9fe2133..d897442 100644 --- a/src/app/(stats)/player/[ign]/_stats/duels/table.tsx +++ b/src/app/(stats)/player/[ign]/_stats/duels/table.tsx @@ -1,6 +1,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { formatNumber } from "@/lib/formatters" -import { getBestDuelsMode, getDuelsModeStats, getModeTitle } from "@/lib/hypixel/duels/duels" +import { getBestDuelsMode, getDevision, getDuelsModeStats, getMode } from "@/lib/hypixel/duels/duels" +import { romanize } from "@/lib/hypixel/general" import { NonNullStats } from "@/lib/schema/player" export default function DuelsStatTable({ stats }: { stats: NonNullStats["Duels"] }) { @@ -72,20 +73,18 @@ function DuelsTableHeader() { ) } -function DuelsStat( - { modeId, stats }: { modeId: Parameters[0], stats: NonNullStats["Duels"] } -) { +function DuelsStat({ modeId, stats }: { modeId: Parameters[0], stats: NonNullStats["Duels"] }) { if (!stats) return null const modeStats = getDuelsModeStats(modeId, stats) - const title = getModeTitle(modeId) + const mode = getMode(modeId) const bestMode = getBestDuelsMode(stats) === modeId - const divisionLabel = "I" + const div = getDevision(mode.divId, stats) return ( - {title} - {divisionLabel} + {mode.name} + {div === null ? "?" : romanize(div.level)} {modeStats.map((v, i) => ( {typeof v === "number" ? formatNumber(v) : v} diff --git a/src/data/hypixel/duels.ts b/src/data/hypixel/duels.ts index 33d2ea9..9e95f7c 100644 --- a/src/data/hypixel/duels.ts +++ b/src/data/hypixel/duels.ts @@ -27,7 +27,7 @@ export const MODES = [ { id: "mw_doubles", divisionId: "mega_walls", name: "MegaWalls Doubles" }, { id: "sumo_duel", divisionId: "sumo", name: "Sumo 1v1" }, { id: "bowspleef_duel", divisionId: "tnt_games", name: "Bow Spleef 1v1" }, - { id: "spleef_duel", divisionId: "", name: "Spleef 1v1" }, + { id: "spleef_duel", divisionId: null, name: "Spleef 1v1" }, { id: "parkour_eight", divisionId: "parkour", name: "Parkour FFA" }, { id: "boxing_duel", divisionId: "boxing", name: "Boxing 1v1" }, { id: "classic_duel", divisionId: "classic", name: "Classic 1v1" }, @@ -40,8 +40,8 @@ export const MODES = [ { id: "bridge_four", divisionId: "bridge", name: "Bridge 4v4" }, { id: "bridge_2v2v2v2", divisionId: "bridge", name: "Bridge 2v2v2v2" }, { id: "bridge_3v3v3v3", divisionId: "bridge", name: "Bridge 3v3v3v3" }, - { id: "duel_arena", divisionId: "", name: "Duel Arena" }, - { id: "quake_duel", divisionId: "quake", name: "Quakecraft 1v1" }, - { id: "bedwars_two_one_duels", divisionId: "bedwars", name: "Bedwars 1v1" }, - { id: "bedwars_two_one_duels_rush", divisionId: "bedwars", name: "Bedwars Rush 1v1" } + { id: "duel_arena", divisionId: null, name: "Duel Arena" }, + { id: "quake_duel", divisionId: null, name: "Quakecraft 1v1" }, + { id: "bedwars_two_one_duels", divisionId: null, name: "Bedwars 1v1" }, + { id: "bedwars_two_one_duels_rush", divisionId: null, name: "Bedwars Rush 1v1" } ] as const diff --git a/src/lib/hypixel/duels/duels.ts b/src/lib/hypixel/duels/duels.ts index 1828c11..f0d745a 100644 --- a/src/lib/hypixel/duels/duels.ts +++ b/src/lib/hypixel/duels/duels.ts @@ -8,11 +8,33 @@ export type Div = { level: number color: typeof DIVISIONS[number]["color"] } +type Mode = typeof MODES[number]["id"] +type Devisions = typeof MODES[number]["divisionId"] -export function getModeTitle(id: typeof MODES[number]["id"]) { +export function getMode(id: typeof MODES[number]["id"]) { const div = MODES.find(d => d.id === id) - return div!.name + return { + name: div!.name, + divId: div!.divisionId + } +} + +export function getDevision(devison: Devisions, stats: NonNullable) { + if (!devison) return null + + for (const div of DIVISIONS.slice().reverse()) { + const index = `${devison}_${div.id}_title_prestige` as const + const val = stats[index] + if (val > 0) { + return { + level: val, + color: div.color + } + } + } + + return null } export function getAllDivisions(stats: NonNullable) { @@ -44,8 +66,6 @@ export function getMostPlayed(stats: NonNullable) { return mostPlayed } -type Mode = typeof MODES[number]["id"] - export function getBestDuelsMode(stats: NonNullable) { let best: typeof MODES[number] | null = null let mostPlays = 0 diff --git a/src/lib/schema/stats.ts b/src/lib/schema/stats.ts index 08af67d..2e69ddd 100644 --- a/src/lib/schema/stats.ts +++ b/src/lib/schema/stats.ts @@ -1,4 +1,5 @@ -import z from "zod" +import { title } from "process" +import z, { object } from "zod" function bedwarsModeStats() { const ids = [ @@ -269,6 +270,49 @@ function duelsModeStats() { } } +function devisionTitles() { + const devisions = [ + "all_modes", + "uhc", + "op", + "skywars", + "bow", + "blitz", + "mega_walls", + "sumo", + "tnt_games", + "parkour", + "boxing", + "classic", + "no_debuff", + "combo", + "bridge" + ] as const + + const titles = [ + "rookie", + "iron", + "gold", + "diamond", + "master", + "legend", + "grandmaster", + "godlike", + "celestial", + "divine", + "ascended" + ] as const + const entries = new Map>() + + for (const div of devisions) { + for (const title of titles) { + entries.set(`${div}_${title}_title_prestige`, z.number().default(-1)) + } + } + + return Object.fromEntries(entries) as Record<`${typeof devisions[number]}_${typeof titles[number]}_title_prestige`, z.ZodDefault> +} + export const duelsStatsSchema = z.looseObject({ wins: z.number().default(0), losses: z.number().default(0), @@ -281,18 +325,7 @@ export const duelsStatsSchema = z.looseObject({ bow_hits: z.number().default(0), current_winstreak: z.number().optional(), best_overall_winstreak: z.number().optional(), - // - all_modes_rookie_title_prestige: z.number().default(-1), - all_modes_iron_title_prestige: z.number().default(-1), - all_modes_gold_title_prestige: z.number().default(-1), - all_modes_diamond_title_prestige: z.number().default(-1), - all_modes_master_title_prestige: z.number().default(-1), - all_modes_legend_title_prestige: z.number().default(-1), - all_modes_grandmaster_title_prestige: z.number().default(-1), - all_modes_godlike_title_prestige: z.number().default(-1), - 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), + ...devisionTitles(), ...duelsModeStats().all, ...duelsModeStats().ws, ...duelsModeStats().bestWs,