Finished sidebar

This commit is contained in:
2025-08-16 23:39:11 +02:00
parent 1921efc76a
commit c79d06f272
35 changed files with 1307 additions and 9 deletions

View File

@@ -0,0 +1,20 @@
import { env } from "../../env/server"
import { guildSchema } from "../../schema/guild"
const guildApi = "https://api.hypixel.net/v2/guild"
export async function getGuild(id: string, type: "id" | "player" | "name" = "player") {
const res = await fetch(`${guildApi}?${type}=${id}`, {
headers: {
"API-Key": env.HYPIXEL_API_KEY
}
})
if (!res.ok) return null
const { success, data } = guildSchema.safeParse(await res.json())
if (!success) return null
return data.guild
}

View File

@@ -0,0 +1,22 @@
import z from "zod"
const mojangApi = "https://api.mojang.com/users/profiles/minecraft"
const schema = z.object({
name: z.string().min(1),
id: z.string().min(1)
})
export async function getUuid(ign: string) {
const res = await fetch(`${mojangApi}/${ign}`)
if (!res.ok) return null
const data = await res.json()
const parsed = schema.safeParse(data)
if (!parsed.success) return null
return parsed.data.id
}

View File

@@ -0,0 +1,20 @@
import { env } from "../../env/server"
import { playerSchema } from "../../schema/player"
const playerApi = "https://api.hypixel.net/v2/player"
export async function getPlayer(uuid: string) {
const res = await fetch(`${playerApi}?uuid=${uuid}`, {
headers: {
"API-Key": env.HYPIXEL_API_KEY
}
})
if (!res.ok) return null
const { success, data } = playerSchema.safeParse(await res.json())
if (!success) return null
return data.player
}

View File

@@ -0,0 +1,9 @@
export function floorLevel(level: number, base: number) {
const extra = level % base
if (extra === 0) {
return level;
}
return level - extra;
}

31
src/lib/hypixel/guild.ts Normal file
View File

@@ -0,0 +1,31 @@
import { object } from "zod"
import { Guild } from "../schema/guild"
export function getGuildMember(guild: Guild["guild"], uuid: string) {
return guild.members.find(m => m.uuid === uuid)
}
export function getGuildRankTag(guild: Guild["guild"], uuid: string) {
const member = getGuildMember(guild, uuid)
return member?.rank === "Guild Master"
? "[GM]"
: `[${guild.ranks.find(r => r.name === member?.rank)?.tag}]`
}
export function getMemberGEXP(guild: Guild["guild"], uuid: string, days: number = 0) {
const member = getGuildMember(guild, uuid)
if (!member) return null
const index = Object.keys(member.expHistory)[days]
return member.expHistory[index]
}
export function getMemberWeeklyGEXP(guild: Guild["guild"], uuid: string) {
const member = getGuildMember(guild, uuid)
if (!member) return null
return Object.values(member.expHistory).reduce((a, b) => a + b)
}

37
src/lib/hypixel/level.ts Normal file
View File

@@ -0,0 +1,37 @@
const BASE = 10000;
const GROWTH = 2500;
const HALF_GROWTH = 0.5 * GROWTH;
const REVERSE_PQ_PREFIX = -(BASE - 0.5 * GROWTH) / GROWTH;
const REVERSE_CONST = REVERSE_PQ_PREFIX * REVERSE_PQ_PREFIX;
const GROWTH_DIVIDES_2 = 2 / GROWTH;
export function getLevel(exp: number) {
return exp <= 1 ? 1 : Math.floor(1 + REVERSE_PQ_PREFIX + Math.sqrt(REVERSE_CONST + GROWTH_DIVIDES_2 * exp));
}
export function getExactLevel(exp: number) {
return getLevel(exp) + getPercentageToNextLevel(exp);
}
// function getExpFromLevelToNext(level: number) {
// return level < 1 ? BASE : GROWTH * (level - 1) + BASE;
// }
function getTotalExpToLevel(level: number) {
const lv = Math.floor(level); const
x0 = getTotalExpToFullLevel(lv);
if (level === lv) return x0;
return (getTotalExpToFullLevel(lv + 1) - x0) * (level % 1) + x0;
}
function getTotalExpToFullLevel(level: number) {
return (HALF_GROWTH * (level - 2) + BASE) * (level - 1);
}
function getPercentageToNextLevel(exp: number) {
const lv = getLevel(exp);
const x0 = getTotalExpToLevel(lv);
return (exp - x0) / (getTotalExpToLevel(lv + 1) - x0);
}

41
src/lib/hypixel/stats.ts Normal file
View File

@@ -0,0 +1,41 @@
import { MULTIPLIER } from "@/data/hypixel/general"
import { Player } from "@/lib/schema/player"
export function getCoinMultiplier(level: number) {
if (level > MULTIPLIER[MULTIPLIER.length - 1].level) {
return MULTIPLIER[MULTIPLIER.length - 1].value;
}
for (let i = MULTIPLIER.length - 1; i >= 0; i--) {
if (level >= MULTIPLIER[i].level) {
return MULTIPLIER[i].value;
}
}
return MULTIPLIER[0].value
}
export function getTotalCoins(stats: Player["player"]["stats"]) {
return Object.values(stats).reduce((total, stat) => total + (stat.coins || 0), 0);
}
export function getTotalQuests(quests: Player["player"]["quests"]) {
return Object.values(quests).reduce((total, quest) => total + (quest.completions?.length || 0), 0);
}
export function getTotalChallenges(challenges: Player["player"]["challenges"]["all_time"]) {
return Object.values(challenges).reduce((total, challenge) => total + challenge, 0);
}
export function rewardClaimed(claimedAt?: number) {
if (!claimedAt) return false
const now = new Date()
const claimedDate = new Date(claimedAt)
const oneDay = 24 * 60 * 60 * 1000
if (now.getMilliseconds() - claimedDate.getMilliseconds() > oneDay) {
return true
} else {
return false
}
}

View File

@@ -0,0 +1,29 @@
"use server"
import { getUuid } from "./api/mojang"
import { getPlayer } from "./api/player"
export async function validatePlayer(ign: string) {
const uuid = await getUuid(ign)
if (!uuid) {
return {
error: true,
message: "Player not found",
}
}
const player = await getPlayer(uuid)
if (!player) {
return {
error: true,
message: "Player never logged on to Hypixel",
}
}
return {
error: false,
message: "Player found",
}
}