Files
hypixel-stats/src/lib/schema/stats.ts

486 lines
15 KiB
TypeScript

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),
winstreak: z.number().optional(),
kills_bedwars: z.number().default(0),
deaths_bedwars: z.number().default(0),
final_kills_bedwars: z.number().default(0),
final_deaths_bedwars: z.number().default(0),
wins_bedwars: z.number().default(0),
losses_bedwars: z.number().default(0),
beds_broken_bedwars: z.number().default(0),
beds_lost_bedwars: z.number().default(0),
total_challenges_completed: z.number().default(0),
iron_resources_collected_bedwars: z.number().default(0),
gold_resources_collected_bedwars: z.number().default(0),
diamond_resources_collected_bedwars: z.number().default(0),
emerald_resources_collected_bedwars: z.number().default(0),
_items_purchased_bedwars: z.number().default(0),
slumber: z.looseObject({
tickets: z.number().default(0),
bag_type: z.string().optional(),
total_tickets_earned: z.number().default(0),
doublers: z.number().default(0),
room: z.record(z.string(), z.boolean()).optional()
}).optional(),
...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(),
kills: z.number().default(0),
deaths: z.number().default(0),
assists: z.number().default(0),
wins: z.number().default(0),
losses: z.number().default(0),
cosmetic_tokens: z.number().default(0),
coins: z.number().default(0),
blocks_placed: z.number().default(0),
blocks_broken: z.number().default(0),
chests_opened: z.number().default(0),
arrows_hit: z.number().default(0),
arrows_shot: z.number().default(0),
melee_kills: z.number().default(0),
void_kills: z.number().default(0),
bow_kills: z.number().default(0),
mobs_kills: z.number().default(0),
enderpearls_thrown: z.number().default(0),
egg_thrown: z.number().default(0),
wins_lab: z.number().default(0),
heads: z.number().default(0),
angel_of_death_level: z.number().default(0),
angels_offering: z.number().default(0),
souls_gathered: z.number().default(0),
souls: z.number().default(0),
paid_souls: z.number().default(0),
soul_well: z.number().default(0),
packages: z.array(z.string()),
shard: z.number().default(0),
opals: z.number().default(0),
heads_eww: z.number().default(0),
heads_yucky: z.number().default(0),
heads_meh: z.number().default(0),
heads_decent: z.number().default(0),
heads_salty: z.number().default(0),
heads_tasty: z.number().default(0),
heads_succulent: z.number().default(0),
heads_sweet: z.number().default(0),
heads_divine: z.number().default(0),
heads_heavenly: z.number().default(0),
head_collection: z.looseObject({
prestigious: z.array(z.object({
username: z.string().nullable().default(null),
timestamp: z.number(),
mode: z.string(),
sacrifice: z.string()
}))
}).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",
"spleef_duel",
"parkour_eight",
"boxing_duel",
"classic_duel",
"classic_doubles",
"potion_duel",
"combo_duel",
"duel_arena",
"quake_duel",
"bedwars_two_one_duels",
"bedwars_two_one_duels_rush"
] as const
const bridgeIds = [
"bridge_duel",
"bridge_doubles",
"bridge_threes",
"bridge_four",
"bridge_2v2v2v2",
"bridge_3v3v3v3"
] as const
const bridgeStats = [
"bridge_kills",
"bridge_deaths",
"goals"
] as const
const stats = [
"kills",
"deaths",
"wins",
"losses",
"melee_swings",
"melee_hits",
"bow_shots",
"bow_hits",
"current_winstreak_mode",
"best_winstreak_mode"
] 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 (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))
}
}
}
const combined = [...stats, ...bridgeStats]
for (const id of bridgeIds) {
for (const stat of combined) {
if (stat === "bridge_kills" || stat === "bridge_deaths" || stat === "goals") {
bridge.set(`${id}_${stat}`, z.number().default(0))
} else if (stat === "best_winstreak_mode") {
ws.set(`${stat}_${id}`, z.number().optional())
} else if (stat === "current_winstreak_mode") {
ws.set(`${stat}_${id}`, z.number().optional())
} else {
entries.set(`${id}_${stat}`, z.number().default(0))
}
}
}
type Modes = typeof ids[number]
type BridgeModes = typeof bridgeIds[number]
type Stats = Exclude<typeof stats[number], "current_winstreak_mode" | "best_winstreak_mode">
type BridgeStats = typeof bridgeStats[number]
return {
all: Object.fromEntries(entries) as Record<`${Modes | BridgeModes}_${Stats}`, z.ZodDefault<z.ZodNumber>>,
ws: Object.fromEntries(ws) as Record<`current_winstreak_mode_${Modes | BridgeModes}`, z.ZodOptional<z.ZodNumber>>,
bestWs: Object.fromEntries(bestWs) as Record<`best_winstreak_mode_${Modes | BridgeModes}`, z.ZodOptional<z.ZodNumber>>,
bridge: Object.fromEntries(bridge) as Record<`${BridgeModes}_${BridgeStats}`, z.ZodDefault<z.ZodNumber>>
}
}
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<string, z.ZodDefault<z.ZodNumber>>()
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<z.ZodNumber>>
}
export const duelsStatsSchema = z.looseObject({
wins: z.number().default(0),
losses: z.number().default(0),
coins: z.number().default(0),
kills: z.number().default(0),
deaths: z.number().default(0),
melee_swings: z.number().default(0),
melee_hits: z.number().default(0),
bow_shots: z.number().default(0),
bow_hits: z.number().default(0),
current_winstreak: z.number().optional(),
best_overall_winstreak: z.number().optional(),
...devisionTitles(),
...duelsModeStats().all,
...duelsModeStats().ws,
...duelsModeStats().bestWs,
...duelsModeStats().bridge
})
function murderMysteryModeStats() {
const ids = [
"MURDER_CLASSIC",
"MURDER_ASSASSINS",
"MURDER_DOUBLE_UP",
"MURDER_HARDCORE",
"MURDER_SHOWDOWN"
] as const
const stats = [
"kills",
"bow_kills",
"knife_kills",
"thrown_knife_kills",
"wins",
"games",
"coins_pickedup"
] 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 murderMysteryStatsSchema = z.looseObject({
kills: z.number().default(0),
deaths: z.number().default(0),
wins: z.number().default(0),
losses: z.number().default(0),
coins: z.number().default(0),
games: z.number().default(0),
bow_kills: z.number().default(0),
knife_kills: z.number().default(0),
coins_pickedup: z.number().default(0),
kills_as_murderer: z.number().default(0),
thrown_knife_kills: z.number().default(0),
active_knife_skin: z.string().optional(),
quickest_detective_win_time_seconds: z.number().default(0),
quickest_murderer_win_time_seconds: z.number().default(0),
kills_as_infected_MURDER_INFECTION: z.number().default(0),
kills_as_survivor_MURDER_INFECTION: z.number().default(0),
kills_MURDER_INFECTION: z.number().default(0),
wins_MURDER_INFECTION: z.number().default(0),
games_MURDER_INFECTION: z.number().default(0),
total_time_survived_seconds_MURDER_INFECTION: z.number().default(0),
coins_pickedup_MURDER_INFECTION: z.number().default(0),
...murderMysteryModeStats()
})
export const buildBattleStatsSchema = z.looseObject({
wins: z.number().default(0),
score: z.number().default(0),
coins: z.number().default(0),
games_played: z.number().default(0),
correct_guesses: z.number().default(0),
super_votes: z.number().default(0),
wins_solo_normal: z.number().default(0),
wins_teams_normal: z.number().default(0),
wins_guess_the_build: z.number().default(0),
wins_solo_pro: z.number().default(0),
wins_speed_builders: z.number().default(0),
wins_solo_normal_latest: z.number().default(0),
wins_teams_normal_latest: z.number().default(0),
wins_guess_the_build_latest: z.number().default(0),
wins_solo_pro_latest: z.number().default(0),
wins_speed_builders_latest: z.number().default(0)
})
function uhcModesStats() {
const ids = [
"solo",
"red_vs_blue",
"no_diamonds",
"vanilla_doubles",
"brawl",
"solo_brawl",
"duo_brawl"
] as const
const stats = [
"wins",
"kills",
"deaths",
"heads_eaten"
] 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 uhcSchema = z.looseObject({
kills: z.number().default(0),
deaths: z.number().default(0),
wins: z.number().default(0),
heads_eaten: z.number().default(0),
score: z.number().default(0),
coins: z.number().default(0),
ultimates_crafted: z.number().default(0),
ultimates_crafted_solo: z.number().default(0),
...uhcModesStats()
})
export const pitStats = z.looseObject({
pit_stats_ptl: z.looseObject({
kills: z.number().default(0),
deaths: z.number().default(0),
cash_earned: z.number().default(0),
playtime_minutes: z.number().default(0),
assists: z.number().default(0),
max_streak: z.number().default(0),
damage_dealt: z.number().default(0),
damage_received: z.number().default(0),
melee_damage_dealt: z.number().default(0),
melee_damage_received: z.number().default(0),
bow_damage_dealt: z.number().default(0),
bow_damage_received: z.number().default(0),
sword_hits: z.number().default(0),
left_clicks: z.number().default(0),
arrow_hits: z.number().default(0),
arrows_fired: z.number().default(0),
contracts_completed: z.number().default(0),
jumped_into_pit: z.number().default(0),
launched_by_launchers: z.number().default(0)
}),
profile: z.looseObject({
prestiges: z.array(z.looseObject({
index: z.number(),
xp_on_prestige: z.number(),
timestamp: z.number()
})).optional(),
xp: z.number().default(0),
cash: z.number().default(0),
renown: z.number().default(0)
})
}).transform(({ profile, pit_stats_ptl, ...rest }) => ({
profile,
...pit_stats_ptl,
...rest
}))