Added first stat on bedwars
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"fmt": "dprint fmt src/**/*.ts src/**/*.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@t3-oss/env-nextjs": "^0.13.8",
|
||||
|
||||
139
pnpm-lock.yaml
generated
139
pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@radix-ui/react-collapsible':
|
||||
specifier: ^1.1.12
|
||||
version: 1.1.12(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@radix-ui/react-separator':
|
||||
specifier: ^1.1.7
|
||||
version: 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
@@ -428,6 +431,22 @@ packages:
|
||||
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
|
||||
engines: {node: '>=12.4.0'}
|
||||
|
||||
'@radix-ui/primitive@1.1.3':
|
||||
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
|
||||
|
||||
'@radix-ui/react-collapsible@1.1.12':
|
||||
resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.2':
|
||||
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
|
||||
peerDependencies:
|
||||
@@ -437,6 +456,37 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-context@1.1.2':
|
||||
resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-id@1.1.1':
|
||||
resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-presence@1.1.5':
|
||||
resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-primitive@2.1.3':
|
||||
resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==}
|
||||
peerDependencies:
|
||||
@@ -472,6 +522,33 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.2.2':
|
||||
resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-effect-event@0.0.2':
|
||||
resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.1':
|
||||
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@rtsao/scc@1.1.0':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
@@ -2278,12 +2355,53 @@ snapshots:
|
||||
|
||||
'@nolyfill/is-core-module@1.0.39': {}
|
||||
|
||||
'@radix-ui/primitive@1.1.3': {}
|
||||
|
||||
'@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
'@types/react-dom': 19.1.6(@types/react@19.1.8)
|
||||
|
||||
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-context@1.1.2(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-id@1.1.1(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
'@types/react-dom': 19.1.6(@types/react@19.1.8)
|
||||
|
||||
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@19.1.0)
|
||||
@@ -2309,6 +2427,27 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@19.1.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@19.1.0)
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.8)(react@19.1.0)':
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.8
|
||||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@rushstack/eslint-patch@1.12.0': {}
|
||||
|
||||
@@ -38,7 +38,9 @@ export default function Sidebar({ level, ign, player, guild }: SidebarProps) {
|
||||
</p>
|
||||
<p>
|
||||
<span className="font-bold">{"Total coins: "}</span>
|
||||
<span className="text-mc-gold">{formatNumber(getTotalCoins(player.stats))}</span>
|
||||
<span className="text-mc-gold">
|
||||
{formatNumber(getTotalCoins(player.stats as Record<string, Record<"coins", number | undefined>>))}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
|
||||
87
src/app/(stats)/player/[ign]/_components/stats/bedewars.tsx
Normal file
87
src/app/(stats)/player/[ign]/_components/stats/bedewars.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
|
||||
import { getBWLevelForExp } from "@/lib/hypixel/bedwarsLevel"
|
||||
import { bedwarsLevelColors } from "@/lib/hypixelFormatters"
|
||||
import { Player } from "@/lib/schema/player"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { ChevronDown, ChevronUp, Menu } from "lucide-react"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
|
||||
export default function BedwarsStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [opened, setOpened] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) return
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === "attributes" && mutation.attributeName === "data-state") {
|
||||
const dataState = ref.current?.getAttribute("data-state")
|
||||
setOpened(dataState === "open")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
observer.observe(ref.current, {
|
||||
attributes: true,
|
||||
attributeFilter: ["data-state"]
|
||||
})
|
||||
|
||||
return () => observer.disconnect()
|
||||
}, [])
|
||||
|
||||
if (!stats) return null
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Collapsible ref={ref}>
|
||||
<div className="flex justify-between">
|
||||
<h1 className="text-xl font-bold">Bedwars</h1>
|
||||
<div className="flex gap-4">
|
||||
<div className="text-center">
|
||||
<p>Level</p>
|
||||
<BedwarsLevel xp={stats.Experience} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 items-center">
|
||||
<CollapsibleTrigger className="transition-all">
|
||||
{opened === false ? <ChevronDown /> : <ChevronUp />}
|
||||
</CollapsibleTrigger>
|
||||
<Menu />
|
||||
</div>
|
||||
</div>
|
||||
<CollapsibleContent>
|
||||
<h1>{stats.Experience}</h1>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
function BedwarsLevel({ xp }: { xp: number }) {
|
||||
const level = getBWLevelForExp(xp)
|
||||
const color = bedwarsLevelColors(level)
|
||||
|
||||
if (typeof color === "string") {
|
||||
return (
|
||||
<p className={cn(color, "font-bold")}>
|
||||
{`[${level}⭐]`}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
const levelArray = `[${level}⭐]`.split("")
|
||||
|
||||
return (
|
||||
<p className="font-bold">
|
||||
{levelArray.map((v, i) => {
|
||||
return <span key={i} className={color[i]}>{v}</span>
|
||||
})}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { getUuid } from "@/lib/hypixel/api/mojang"
|
||||
import { getPlayer } from "@/lib/hypixel/api/player"
|
||||
import { getExactLevel } from "@/lib/hypixel/level"
|
||||
import Sidebar from "./_components/Sidebar"
|
||||
import BedwarsStats from "./_components/stats/bedewars"
|
||||
|
||||
export default async function PlayerPage({
|
||||
params
|
||||
@@ -53,9 +54,8 @@ export default async function PlayerPage({
|
||||
</h1>
|
||||
<div className="flex gap-6 px-6 mt-8 w-full max-w-7xl">
|
||||
<Sidebar level={level} ign={pign} player={player} guild={guild ?? undefined} />
|
||||
<div className="p-6 w-3/4 rounded-xl border shadow-sm bg-card">
|
||||
<h2 className="mb-4 text-xl font-semibold">Game Statistics</h2>
|
||||
<p>Game stats will be displayed here...</p>
|
||||
<div className="w-3/4">
|
||||
<BedwarsStats stats={player.stats.Bedwars} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
33
src/components/ui/collapsible.tsx
Normal file
33
src/components/ui/collapsible.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
"use client"
|
||||
|
||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
|
||||
|
||||
function Collapsible({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
|
||||
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
|
||||
}
|
||||
|
||||
function CollapsibleTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
|
||||
return (
|
||||
<CollapsiblePrimitive.CollapsibleTrigger
|
||||
data-slot="collapsible-trigger"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function CollapsibleContent({
|
||||
...props
|
||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
|
||||
return (
|
||||
<CollapsiblePrimitive.CollapsibleContent
|
||||
data-slot="collapsible-content"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
||||
@@ -34,3 +34,42 @@ export function getColor(color?: string, type: "text" | "bg" = "text", defaultCo
|
||||
return type === "text" ? `text-mc-${defaultColor}` : `bg-mc-${defaultColor}`
|
||||
}
|
||||
}
|
||||
|
||||
export function getColorFromCode(c?: string) {
|
||||
switch (c) {
|
||||
case "0":
|
||||
return "text-mc-black"
|
||||
case "1":
|
||||
return "text-mc-dark-blue"
|
||||
case "2":
|
||||
return "text-mc-dark-green"
|
||||
case "3":
|
||||
return "text-mc-dark-aqua"
|
||||
case "4":
|
||||
return "text-mc-dark-red"
|
||||
case "5":
|
||||
return "text-mc-dark-purple"
|
||||
case "6":
|
||||
return "text-mc-gold"
|
||||
case "7":
|
||||
return "text-mc-gray"
|
||||
case "8":
|
||||
return "text-mc-dark-gray"
|
||||
case "9":
|
||||
return "text-mc-blue"
|
||||
case "a":
|
||||
return "text-mc-green"
|
||||
case "b":
|
||||
return "text-mc-aqua"
|
||||
case "c":
|
||||
return "text-mc-red"
|
||||
case "d":
|
||||
return "text-mc-light-purple"
|
||||
case "e":
|
||||
return "text-mc-yellow"
|
||||
case "f":
|
||||
return "text-mc-white"
|
||||
default:
|
||||
return "text-mc-gray"
|
||||
}
|
||||
}
|
||||
|
||||
126
src/data/hypixel/bedwars.ts
Normal file
126
src/data/hypixel/bedwars.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
export const TITLE = "Bed Wars"
|
||||
export const PRESTIGES = [
|
||||
{ level: 0, colormap: "7", color: "gray", name: "None" },
|
||||
{ level: 100, colormap: "f", color: "white", name: "Iron" },
|
||||
{ level: 200, colormap: "6", color: "gold", name: "Gold" },
|
||||
{ level: 300, colormap: "b", color: "aqua", name: "Diamond" },
|
||||
{ level: 400, colormap: "2", color: "darkgreen", name: "Emerald" },
|
||||
{ level: 500, colormap: "3", color: "darkaqua", name: "Sapphire" },
|
||||
{ level: 600, colormap: "4", color: "darkred", name: "Ruby" },
|
||||
{ level: 700, colormap: "d", color: "pink", name: "Crystal" },
|
||||
{ level: 800, colormap: "9", color: "blue", name: "Opal" },
|
||||
{ level: 900, colormap: "5", color: "purple", name: "Amethyst" },
|
||||
{ level: 1000, colormap: "c6eabd5", color: "rainbow", name: "Rainbow" },
|
||||
{ level: 1100, colormap: "7ffff77", color: "white", name: "Iron Prime" },
|
||||
{ level: 1200, colormap: "7eeee67", color: "yellow", name: "Gold Prime" },
|
||||
{ level: 1300, colormap: "7bbbb37", color: "aqua", name: "Diamond Prime" },
|
||||
{ level: 1400, colormap: "7aaaa27", color: "green", name: "Emerald Prime" },
|
||||
{ level: 1500, colormap: "7333397", color: "darkaqua", name: "Sapphire Prime" },
|
||||
{ level: 1600, colormap: "7cccc47", color: "red", name: "Ruby Prime" },
|
||||
{ level: 1700, colormap: "7dddd57", color: "pink", name: "Crystal Prime" },
|
||||
{ level: 1800, colormap: "7999917", color: "blue", name: "Opal Prime" },
|
||||
{ level: 1900, colormap: "7555587", color: "purple", name: "Amethyst Prime" },
|
||||
{ level: 2000, colormap: "87ff778", color: "white", name: "Mirror" },
|
||||
{ level: 2100, colormap: "ffee666", color: "yellow", name: "Light" },
|
||||
{ level: 2200, colormap: "66ffb33", color: "aqua", name: "Dawn" },
|
||||
{ level: 2300, colormap: "55dd6ee", color: "purple", name: "Dusk" },
|
||||
{ level: 2400, colormap: "bbff778", color: "white", name: "Air" },
|
||||
{ level: 2500, colormap: "ffaa222", color: "green", name: "Wind" },
|
||||
{ level: 2600, colormap: "44ccdd5", color: "darkred", name: "Nebula" },
|
||||
{ level: 2700, colormap: "eeff777", color: "yellow", name: "Thunder" },
|
||||
{ level: 2800, colormap: "aa2266e", color: "darkgreen", name: "Earth" },
|
||||
{ level: 2900, colormap: "bb33991", color: "blue", name: "Water" },
|
||||
{ level: 3000, colormap: "ee66cc4", color: "red", name: "Fire" },
|
||||
{ level: 3100, colormap: "993366e", color: "blue", name: "Sunshine" },
|
||||
{ level: 3200, colormap: "c4774cc", color: "darkred", name: "Eclipse" },
|
||||
{ level: 3300, colormap: "999dcc4", color: "blue", name: "Gamma" },
|
||||
{ level: 3400, colormap: "2add552", color: "green", name: "Majestic" },
|
||||
{ level: 3500, colormap: "cc442aa", color: "red", name: "Andesine" },
|
||||
{ level: 3600, colormap: "aaab991", color: "green", name: "Marine" },
|
||||
{ level: 3700, colormap: "44ccb33", color: "darkred", name: "Element" },
|
||||
{ level: 3800, colormap: "11955d1", color: "darkblue", name: "Galaxy" },
|
||||
{ level: 3900, colormap: "ccaa399", color: "red", name: "Atomic" },
|
||||
{ level: 4000, colormap: "55cc66e", color: "purple", name: "Sunset" },
|
||||
{ level: 4100, colormap: "ee6cdd5", color: "yellow", name: "Time" },
|
||||
{ level: 4200, colormap: "193bf77", color: "blue", name: "Winter" },
|
||||
{ level: 4300, colormap: "0588550", color: "purple", name: "Obsidian" },
|
||||
{ level: 4400, colormap: "22ae65d", color: "darkgreen", name: "Spring" },
|
||||
{ level: 4500, colormap: "ffbb333", color: "white", name: "Ice" },
|
||||
{ level: 4600, colormap: "3bee6d5", color: "aqua", name: "Summer" },
|
||||
{ level: 4700, colormap: "f4cc919", color: "darkred", name: "Spinel" },
|
||||
{ level: 4800, colormap: "55c6eb3", color: "purple", name: "Autumn" },
|
||||
{ level: 4900, colormap: "2affaa2", color: "green", name: "Mystic" },
|
||||
{ level: 5000, colormap: "4459910", color: "darkred", name: "Eternal" }
|
||||
]
|
||||
export const PRESTIGE_ICONS = [
|
||||
{ level: 0, symbol: "✫" },
|
||||
{ level: 1100, symbol: "✪" },
|
||||
{ level: 2100, symbol: "⚝" },
|
||||
{ level: 3100, symbol: "✥" }
|
||||
]
|
||||
export const MODES = [
|
||||
{ id: "eight_one_", name: "Solo" },
|
||||
{ id: "eight_two_", name: "Doubles" },
|
||||
{ id: "four_three_", name: "3v3v3v3" },
|
||||
{ id: "four_four_", name: "4v4v4v4" },
|
||||
{ id: "two_four_", name: "4v4" },
|
||||
{ id: "eight_one_rush_", name: "Rush Solo" },
|
||||
{ id: "eight_two_rush_", name: "Rush Doubles" },
|
||||
{ id: "four_four_rush_", name: "Rush 4v4v4v4" },
|
||||
{ id: "eight_one_ultimate_", name: "Ultimate Solo" },
|
||||
{ id: "eight_two_ultimate_", name: "Ultimate Doubles" },
|
||||
{ id: "four_four_ultimate_", name: "Ultimate 4v4v4v4" },
|
||||
{ id: "eight_two_lucky_", name: "Lucky Doubles" },
|
||||
{ id: "four_four_lucky_", name: "Lucky 4v4v4v4" },
|
||||
{ id: "eight_two_voidless_", name: "Voidless Doubles" },
|
||||
{ id: "four_four_voidless_", name: "Voidless 4v4v4v4" },
|
||||
{ id: "eight_two_armed_", name: "Armed Doubles" },
|
||||
{ id: "four_four_armed_", name: "Armed 4v4v4v4" },
|
||||
{ id: "eight_two_swap_", name: "Swappage Doubles" },
|
||||
{ id: "four_four_swap_", name: "Swappage 4v4v4v4" },
|
||||
{ id: "eight_two_underworld_", name: "Underworld Doubles" },
|
||||
{ id: "four_four_underworld_", name: "Underworld 4v4v4v4" },
|
||||
{ id: "castle_", name: "Castle" },
|
||||
{ id: "", name: "Overall" }
|
||||
]
|
||||
export const PRACTICEMODES = [
|
||||
{ id: "bridging", name: "Bridging" },
|
||||
{ id: "mlg", name: "MLG" },
|
||||
{ id: "fireball_jumping", name: "Fireball/TNT Jumping" },
|
||||
{ id: "pearl_clutching", name: "Pearl Clutching" }
|
||||
]
|
||||
export const PRACTICEBRIDGING = {
|
||||
bridging_distance: [30, 50, 100],
|
||||
elevation: [
|
||||
{ id: "NONE", name: "Flat" },
|
||||
{ id: "SLIGHT", name: "Inclined" },
|
||||
{ id: "STAIRCASE", name: "Stairs" }
|
||||
],
|
||||
angle: [
|
||||
{ id: "STRAIGHT", name: "Straight" },
|
||||
{ id: "DIAGONAL", name: "Diagonal" }
|
||||
]
|
||||
}
|
||||
export const SLUMBER_WALLETS = {
|
||||
"MINI_WALLET": 25,
|
||||
"LIGHT_SLUMBERS_WALLET": 99,
|
||||
"LIGHT_IMPERIAL_WALLET": 500,
|
||||
"EXPLORERS_WALLET": 5000,
|
||||
"HOTEL_STAFF_WALLET": 10000,
|
||||
"PLATINUM_MEMBERSHIP_WALLET": 100000
|
||||
}
|
||||
export const SLUMBER_ROOMS = [
|
||||
{ id: "room_1", name: "Throne Door" },
|
||||
{ id: "room_2", name: "Hotel Door" },
|
||||
{ id: "room_3", name: "Desert Door" },
|
||||
{ id: "room_4", name: "Electronic Door" },
|
||||
{ id: "room_5", name: "Door from the Sky" },
|
||||
{ id: "room_6", name: "Door as seen on TV" },
|
||||
{ id: "room_7", name: "Skyscraper Door" },
|
||||
{ id: "room_8", name: "Arcade Door" },
|
||||
{ id: "room_9", name: "Intricate Door" },
|
||||
{ id: "room_10", name: "Space Door" },
|
||||
{ id: "room_11", name: "D\xa0\xa0\xa0o\xa0\xa00\xa0\xa0\xa0\xa0\xa0\xa0r" },
|
||||
{ id: "room_12", name: "Garage Door" },
|
||||
{ id: "owners_office", name: "Owner's Office" }
|
||||
]
|
||||
55
src/lib/hypixel/bedwarsLevel.ts
Normal file
55
src/lib/hypixel/bedwarsLevel.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Functions for BedWars exp and level conversions.
|
||||
*/
|
||||
const EASY_LEVELS = 4
|
||||
const EASY_LEVELS_XP = 7000
|
||||
const XP_PER_PRESTIGE = 96 * 5000 + EASY_LEVELS_XP
|
||||
const LEVELS_PER_PRESTIGE = 100
|
||||
const HIGHEST_PRESTIGE = 10
|
||||
|
||||
export function getBWLevel(level: number) {
|
||||
if (level > HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE) {
|
||||
return level - HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE
|
||||
}
|
||||
|
||||
return level % LEVELS_PER_PRESTIGE
|
||||
}
|
||||
|
||||
export function getBWExpForLevel(level: number) {
|
||||
if (level === 0) return 0
|
||||
|
||||
const respectedLevel = getBWLevel(level)
|
||||
if (respectedLevel > EASY_LEVELS) {
|
||||
return 5000
|
||||
}
|
||||
|
||||
switch (respectedLevel) {
|
||||
case 1:
|
||||
return 500
|
||||
case 2:
|
||||
return 1000
|
||||
case 3:
|
||||
return 2000
|
||||
case 4:
|
||||
return 3500
|
||||
default:
|
||||
return 5000
|
||||
}
|
||||
}
|
||||
|
||||
export function getBWLevelForExp(exp: number) {
|
||||
const prestiges = Math.floor(exp / XP_PER_PRESTIGE)
|
||||
let level = prestiges * LEVELS_PER_PRESTIGE
|
||||
let expWithoutPrestiges = exp - (prestiges * XP_PER_PRESTIGE)
|
||||
let expForEasyLevel
|
||||
|
||||
for (let i = 1; i <= EASY_LEVELS; i += 1) {
|
||||
expForEasyLevel = getBWExpForLevel(i)
|
||||
if (expWithoutPrestiges < expForEasyLevel) {
|
||||
break
|
||||
}
|
||||
level += 1
|
||||
expWithoutPrestiges -= expForEasyLevel
|
||||
}
|
||||
return level + Math.floor(expWithoutPrestiges / 5000)
|
||||
}
|
||||
@@ -3,28 +3,28 @@ import { Player } from "@/lib/schema/player"
|
||||
|
||||
export function getCoinMultiplier(level: number) {
|
||||
if (level > MULTIPLIER[MULTIPLIER.length - 1].level) {
|
||||
return MULTIPLIER[MULTIPLIER.length - 1].value;
|
||||
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[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 getTotalCoins(stats: Record<string, Record<"coins", number | undefined>>) {
|
||||
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);
|
||||
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);
|
||||
return Object.values(challenges).reduce((total, challenge) => total + challenge, 0)
|
||||
}
|
||||
|
||||
export function rewardClaimed(claimedAt?: number) {
|
||||
@@ -39,3 +39,4 @@ export function rewardClaimed(claimedAt?: number) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
src/lib/hypixelFormatters.ts
Normal file
23
src/lib/hypixelFormatters.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { getColorFromCode } from "@/data/colors"
|
||||
import { PRESTIGES } from "@/data/hypixel/bedwars"
|
||||
import { floorLevel } from "./hypixel/formatters"
|
||||
|
||||
export function bedwarsLevelColors(level: number) {
|
||||
if (level < 0) return getColorFromCode()
|
||||
|
||||
const floored = floorLevel(level, 100)
|
||||
|
||||
if (floored < 1000) {
|
||||
return getColorFromCode(PRESTIGES.find(v => v.level === floored)!.colormap)
|
||||
}
|
||||
|
||||
if (floored > 5000) {
|
||||
return PRESTIGES[PRESTIGES.length - 1].colormap.split("").map(v => {
|
||||
return getColorFromCode(v)
|
||||
})
|
||||
}
|
||||
|
||||
return PRESTIGES.find(v => v.level === floored)!.colormap.split("").map(v => {
|
||||
return getColorFromCode(v)
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import z from "zod"
|
||||
|
||||
export const playerSchema = z.object({
|
||||
player: z.object({
|
||||
export const playerSchema = z.looseObject({
|
||||
player: z.looseObject({
|
||||
displayname: z.string(),
|
||||
uuid: z.string(),
|
||||
newPackageRank: z.literal("VIP").or(z.literal("VIP_PLUS").or(z.literal("MVP")).or(z.literal("MVP_PLUS"))).optional(),
|
||||
@@ -11,37 +11,36 @@ export const playerSchema = z.object({
|
||||
networkExp: z.number(),
|
||||
karma: z.number(),
|
||||
achievementPoints: z.number().optional(),
|
||||
stats: z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
coins: z.number().optional()
|
||||
})
|
||||
),
|
||||
stats: z.looseObject({
|
||||
Bedwars: z.looseObject({
|
||||
Experience: z.number()
|
||||
}).optional()
|
||||
}),
|
||||
quests: z.record(
|
||||
z.string(),
|
||||
z.object({
|
||||
z.looseObject({
|
||||
completions: z.array(
|
||||
z.object({
|
||||
z.looseObject({
|
||||
time: z.number()
|
||||
}).optional()
|
||||
).optional()
|
||||
})
|
||||
),
|
||||
challenges: z.object({
|
||||
challenges: z.looseObject({
|
||||
all_time: z.record(z.string(), z.number())
|
||||
}),
|
||||
lastClaimedReward: z.number().optional(),
|
||||
rewardHighScore: z.number().optional(),
|
||||
rewardStreak: z.number().optional(),
|
||||
totalRewards: z.number().optional(),
|
||||
giftingMeta: z.object({
|
||||
giftingMeta: z.looseObject({
|
||||
giftsGiven: z.number().optional(),
|
||||
ranksGiven: z.number().optional()
|
||||
}).optional(),
|
||||
firstLogin: z.number().optional(),
|
||||
lastLogin: z.number().optional(),
|
||||
socialMedia: z.object({
|
||||
links: z.object({
|
||||
socialMedia: z.looseObject({
|
||||
links: z.looseObject({
|
||||
DISCORD: z.string().optional(),
|
||||
TWITCH: z.string().optional(),
|
||||
HYPIXEL: z.string().optional(),
|
||||
@@ -53,4 +52,3 @@ export const playerSchema = z.object({
|
||||
})
|
||||
|
||||
export type Player = z.infer<typeof playerSchema>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user