Use website for berry dash leaderboards
This commit is contained in:
5 files changed
+18
-392
No files matched your search
@@ -1,358 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import './styles.css'
|
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
|
||||||
import { BirdColor } from '@/types/BerryDash/BirdColor'
|
|
||||||
import { GetIconForUser } from '@/lib/berrydashutil'
|
|
||||||
import Image from 'next/image'
|
|
||||||
import { useRouter } from 'next/navigation'
|
|
||||||
import { arch, platform } from '@tauri-apps/plugin-os'
|
|
||||||
import { fetch } from '@tauri-apps/plugin-http'
|
|
||||||
import { verifySignature } from '@/lib/util'
|
|
||||||
import Dropdown from '@/components/Dropdown'
|
|
||||||
import { app } from '@tauri-apps/api'
|
|
||||||
|
|
||||||
interface BaseEntry {
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
value: number
|
|
||||||
icon: number
|
|
||||||
overlay: number
|
|
||||||
birdColor: BirdColor
|
|
||||||
overlayColor: BirdColor
|
|
||||||
customIcon: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Stats {
|
|
||||||
highScore: string
|
|
||||||
totalNormalBerries: string
|
|
||||||
totalPoisonBerries: string
|
|
||||||
totalSlowBerries: string
|
|
||||||
totalUltraBerries: string
|
|
||||||
totalSpeedyBerries: string
|
|
||||||
totalCoinBerries: string
|
|
||||||
totalRandomBerries: string
|
|
||||||
totalAntiBerries: string
|
|
||||||
totalGoldenBerries: string
|
|
||||||
coins: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LeaderboardEntry extends BaseEntry {
|
|
||||||
type: 'leaderboard'
|
|
||||||
value: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Account extends BaseEntry {
|
|
||||||
type: 'account'
|
|
||||||
stats: Stats
|
|
||||||
xp: bigint
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateXP (
|
|
||||||
normalBerries: bigint,
|
|
||||||
poisonBerries: bigint,
|
|
||||||
slowBerries: bigint,
|
|
||||||
ultraBerries: bigint,
|
|
||||||
speedyBerries: bigint,
|
|
||||||
coinBerries: bigint,
|
|
||||||
randomBerries: bigint,
|
|
||||||
antiBerries: bigint,
|
|
||||||
goldenBerries: bigint
|
|
||||||
): bigint {
|
|
||||||
let totalXp = 0n
|
|
||||||
totalXp += normalBerries
|
|
||||||
totalXp -= poisonBerries
|
|
||||||
totalXp -= slowBerries
|
|
||||||
totalXp += ultraBerries * 5n
|
|
||||||
totalXp += speedyBerries * 10n
|
|
||||||
totalXp += coinBerries * 10n
|
|
||||||
totalXp += randomBerries
|
|
||||||
totalXp -= antiBerries
|
|
||||||
totalXp += goldenBerries * 4n
|
|
||||||
|
|
||||||
if (totalXp < 0n) totalXp = 0n
|
|
||||||
return totalXp
|
|
||||||
}
|
|
||||||
|
|
||||||
export function calculateLevel (xp: bigint): number {
|
|
||||||
const levelDivisor = 50.0
|
|
||||||
|
|
||||||
const xpNumber = Number(xp)
|
|
||||||
const discriminant = 95 * 95 + levelDivisor * 2 * xpNumber
|
|
||||||
const level = (-95 + Math.sqrt(discriminant)) / levelDivisor
|
|
||||||
return Math.floor(level) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function BerryDashLeaderboards () {
|
|
||||||
const [selected, setSelected] = useState<number>(-1)
|
|
||||||
const [selectedBerryOption, setSelectedBerryOption] = useState<number>(0)
|
|
||||||
const [entries, setEntries] = useState<(LeaderboardEntry | Account)[]>([])
|
|
||||||
const [loading, setLoading] = useState<boolean>(false)
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const Refresh = useCallback(async () => {
|
|
||||||
setLoading(true)
|
|
||||||
try {
|
|
||||||
if (selected == 3 || selected == 4) {
|
|
||||||
const response = await fetch(
|
|
||||||
'https://games.lncvrt.xyz/api/berrydash/account?username=',
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Requester: 'LncvrtGamesLauncherClient',
|
|
||||||
ClientVersion: await app.getVersion(),
|
|
||||||
ClientPlatform: platform() + '-' + arch()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const signature = response.headers.get('x-signature') ?? ''
|
|
||||||
const data = await response.json()
|
|
||||||
if (
|
|
||||||
(await verifySignature(JSON.stringify(data), signature)) &&
|
|
||||||
data.success
|
|
||||||
) {
|
|
||||||
let accounts = data.data as Account[]
|
|
||||||
|
|
||||||
accounts = accounts.map(acc => {
|
|
||||||
const xp = calculateXP(
|
|
||||||
BigInt(acc.stats.totalNormalBerries),
|
|
||||||
BigInt(acc.stats.totalPoisonBerries),
|
|
||||||
BigInt(acc.stats.totalSlowBerries),
|
|
||||||
BigInt(acc.stats.totalUltraBerries),
|
|
||||||
BigInt(acc.stats.totalSpeedyBerries),
|
|
||||||
BigInt(acc.stats.totalCoinBerries),
|
|
||||||
BigInt(acc.stats.totalRandomBerries),
|
|
||||||
BigInt(acc.stats.totalAntiBerries),
|
|
||||||
BigInt(acc.stats.totalGoldenBerries)
|
|
||||||
)
|
|
||||||
return { ...acc, xp }
|
|
||||||
})
|
|
||||||
|
|
||||||
accounts.sort((a, b) => (b.xp > a.xp ? 1 : b.xp < a.xp ? -1 : 0))
|
|
||||||
|
|
||||||
setEntries(accounts)
|
|
||||||
} else console.log('Failed')
|
|
||||||
} else {
|
|
||||||
const response = await fetch(
|
|
||||||
'https://games.lncvrt.xyz/api/berrydash/leaderboard/' +
|
|
||||||
(selected == 0
|
|
||||||
? 'score'
|
|
||||||
: selected == 1
|
|
||||||
? 'berry?berry=' + selectedBerryOption
|
|
||||||
: selected == 2
|
|
||||||
? 'coin'
|
|
||||||
: selected == 5
|
|
||||||
? 'legacy'
|
|
||||||
: 'total'),
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Requester: 'LncvrtGamesLauncherClient',
|
|
||||||
ClientVersion: await app.getVersion(),
|
|
||||||
ClientPlatform: platform() + '-' + arch()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
const signature = response.headers.get('x-signature') ?? ''
|
|
||||||
const data = await response.json()
|
|
||||||
if (
|
|
||||||
(await verifySignature(JSON.stringify(data), signature)) &&
|
|
||||||
data.success
|
|
||||||
)
|
|
||||||
setEntries(data.data as LeaderboardEntry[])
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setEntries([])
|
|
||||||
}
|
|
||||||
setLoading(false)
|
|
||||||
}, [selected, selectedBerryOption])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.title = 'Lncvrt Games - Berry Dash Leaderboards'
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selected != -1) setTimeout(() => Refresh(), 0)
|
|
||||||
}, [selected, Refresh])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='mx-4 mt-4'>
|
|
||||||
<div className='flex justify-between items-center mb-4'>
|
|
||||||
<p className='text-3xl'>Berry Dash Leaderboards</p>
|
|
||||||
<div className='flex gap-2'>
|
|
||||||
{selected == 1 && (
|
|
||||||
<div className='flex justify-center'>
|
|
||||||
<Dropdown
|
|
||||||
value={selectedBerryOption}
|
|
||||||
options={[
|
|
||||||
{ label: 'Normal Berry', value: 0 },
|
|
||||||
{ label: 'Poison Berry', value: 1 },
|
|
||||||
{ label: 'Slow Berry', value: 2 },
|
|
||||||
{ label: 'Ultra Berry', value: 3 },
|
|
||||||
{ label: 'Speedy Berry', value: 4 },
|
|
||||||
{ label: 'Coin Berry', value: 5 },
|
|
||||||
{ label: 'Random Berry', value: 6 },
|
|
||||||
{ label: 'Anti Berry', value: 7 },
|
|
||||||
{ label: 'Golden Berry', value: 8 }
|
|
||||||
]}
|
|
||||||
onChange={e => setSelectedBerryOption(Number(e))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
className='button btntheme1'
|
|
||||||
onClick={() => {
|
|
||||||
setEntries([])
|
|
||||||
Refresh()
|
|
||||||
}}
|
|
||||||
title='Click to refresh the leaderboards.'
|
|
||||||
hidden={selected == -1}
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='button btntheme1'
|
|
||||||
onClick={() => {
|
|
||||||
if (selected == -1) router.push('/main/game?id=1')
|
|
||||||
else {
|
|
||||||
setSelected(-1)
|
|
||||||
setSelectedBerryOption(0)
|
|
||||||
setEntries([])
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
title='Click to go up a level.'
|
|
||||||
>
|
|
||||||
Back
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`box ${
|
|
||||||
platform() == 'windows'
|
|
||||||
? 'h-[calc(100vh-116px)]'
|
|
||||||
: 'h-[calc(100vh-84px)]'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{selected == -1 ? (
|
|
||||||
<>
|
|
||||||
<p className='text-center mt-2 text-xl'>Select a Leaderboard</p>
|
|
||||||
<div className='flex flex-col gap-2 mt-2 items-center justify-center'>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(0)}
|
|
||||||
>
|
|
||||||
Score Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(1)}
|
|
||||||
>
|
|
||||||
Berry Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(2)}
|
|
||||||
>
|
|
||||||
Coins Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(3)}
|
|
||||||
>
|
|
||||||
Level Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(4)}
|
|
||||||
>
|
|
||||||
Total XP Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(5)}
|
|
||||||
>
|
|
||||||
Legacy Leaderboard
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className='leaderboard-button'
|
|
||||||
onClick={() => setSelected(6)}
|
|
||||||
>
|
|
||||||
Total Berries Leaderboard
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : loading ? (
|
|
||||||
<p className='flex justify-center items-center text-6xl h-full'>
|
|
||||||
Loading
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
className={`flex flex-col gap-2 overflow-y-auto ${
|
|
||||||
platform() == 'windows'
|
|
||||||
? 'h-[calc(100vh-128px)]'
|
|
||||||
: 'h-[calc(100vh-96px)]'
|
|
||||||
} px-1`}
|
|
||||||
>
|
|
||||||
{entries.map((item, index) => {
|
|
||||||
const isAccount = 'stats' in item
|
|
||||||
const isLeaderboard = 'value' in item && !isAccount
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
className='leaderboard-entry flex justify-between items-center'
|
|
||||||
>
|
|
||||||
<div className='flex items-center gap-1'>
|
|
||||||
<Image
|
|
||||||
src={
|
|
||||||
!item.customIcon
|
|
||||||
? `https://games.lncvrt.xyz/api/berrydash/render-icon?icon=${
|
|
||||||
item.icon == 1
|
|
||||||
? GetIconForUser(item.id)
|
|
||||||
: item.icon
|
|
||||||
}&overlay=${item.overlay}&birdR=${
|
|
||||||
item.birdColor[0]
|
|
||||||
}&birdG=${item.birdColor[1]}&birdB=${
|
|
||||||
item.birdColor[2]
|
|
||||||
}&overlayR=${item.overlayColor[0]}&overlayG=${
|
|
||||||
item.overlayColor[1]
|
|
||||||
}&overlayB=${item.overlayColor[2]}`
|
|
||||||
: `https://games.lncvrt.xyz/api/berrydash/icon-marketplace/icon?id=${item.customIcon}&raw=true`
|
|
||||||
}
|
|
||||||
width={48}
|
|
||||||
height={48}
|
|
||||||
alt=''
|
|
||||||
className='pointer-events-none scale-x-[-1]'
|
|
||||||
/>
|
|
||||||
<p>
|
|
||||||
{item.username} (#{index + 1})
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isLeaderboard ? (
|
|
||||||
<p>
|
|
||||||
{selected === 1 || selected === 6
|
|
||||||
? 'Berries'
|
|
||||||
: selected === 2
|
|
||||||
? 'Coins'
|
|
||||||
: 'Score'}
|
|
||||||
: {item.value.toLocaleString()}
|
|
||||||
</p>
|
|
||||||
) : isAccount ? (
|
|
||||||
<p>
|
|
||||||
{selected === 3 ? 'Level' : 'XP'}:{' '}
|
|
||||||
{selected === 3
|
|
||||||
? calculateLevel(item.xp).toLocaleString()
|
|
||||||
: item.xp.toLocaleString()}
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
@import "tailwindcss";
|
|
||||||
|
|
||||||
.box {
|
|
||||||
@apply bg-(--col1) border border-(--col3) rounded-lg w-auto p-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaderboard-button {
|
|
||||||
@apply bg-(--col2) hover:bg-(--col4) border border-(--col4) hover:border-(--col6) rounded-lg px-4 py-2 inline-block transition-all cursor-pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaderboard-entry {
|
|
||||||
@apply rounded-lg text-gray-200 text-lg px-1 py-0.5 transition-colors bg-(--col2) hover:bg-(--col3) border border-(--col4) hover:border-(--col5) cursor-pointer;
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ import '../Installs.css'
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { useGlobal } from '@/providers/GlobalProvider'
|
import { useGlobal } from '@/providers/GlobalProvider'
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
import { useSearchParams } from 'next/navigation'
|
||||||
import { platform } from '@tauri-apps/plugin-os'
|
import { platform } from '@tauri-apps/plugin-os'
|
||||||
import { faWarning } from '@fortawesome/free-solid-svg-icons'
|
import { faWarning } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
@@ -30,11 +30,11 @@ export default function Installs () {
|
|||||||
customDataLocation,
|
customDataLocation,
|
||||||
needsRevisionUpdate,
|
needsRevisionUpdate,
|
||||||
launchGame,
|
launchGame,
|
||||||
developerMode
|
developerMode,
|
||||||
|
theme
|
||||||
} = useGlobal()
|
} = useGlobal()
|
||||||
|
|
||||||
const params = useSearchParams()
|
const params = useSearchParams()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const id = Number(params.get('id') || 0)
|
const id = Number(params.get('id') || 0)
|
||||||
const game = serverVersionList?.games.find(g => g.id === id)
|
const game = serverVersionList?.games.find(g => g.id === id)
|
||||||
@@ -73,9 +73,17 @@ export default function Installs () {
|
|||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
<button
|
<button
|
||||||
className='button btntheme1'
|
className='button btntheme1'
|
||||||
onClick={() => {
|
onClick={() =>
|
||||||
router.push('/main/game/berrydash/leaderboards')
|
invoke('open_new_window', {
|
||||||
}}
|
title: 'Berry Dash Leaderboards',
|
||||||
|
name: 'berrydashleaderboards',
|
||||||
|
url:
|
||||||
|
'https://games.lncvrt.xyz/game/berry-dash/leaderboards?launcher=1&theme=' +
|
||||||
|
theme,
|
||||||
|
width: 800,
|
||||||
|
height: 600
|
||||||
|
})
|
||||||
|
}
|
||||||
title='View the leaderboards for this game.'
|
title='View the leaderboards for this game.'
|
||||||
hidden={game.id != 1}
|
hidden={game.id != 1}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -132,10 +132,8 @@ export default function Sidebar () {
|
|||||||
<div
|
<div
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className={`link ${
|
className={`link ${
|
||||||
(pathname === '/main/game' &&
|
pathname === '/main/game' &&
|
||||||
Number(params.get('id') || 0) == i.id) ||
|
Number(params.get('id') || 0) == i.id
|
||||||
(i.id == 1 &&
|
|
||||||
pathname === '/main/game/berrydash/leaderboards')
|
|
||||||
? 'active'
|
? 'active'
|
||||||
: ''
|
: ''
|
||||||
} ml-auto w-50 ${
|
} ml-auto w-50 ${
|
||||||
@@ -191,10 +189,8 @@ export default function Sidebar () {
|
|||||||
key={`${i.id}-${key}`}
|
key={`${i.id}-${key}`}
|
||||||
draggable={false}
|
draggable={false}
|
||||||
className={`link ${
|
className={`link ${
|
||||||
((pathname === '/main/game' &&
|
pathname === '/main/game' &&
|
||||||
Number(params.get('id') || 0) == i.id) ||
|
Number(params.get('id') || 0) == i.id &&
|
||||||
(i.id == 1 &&
|
|
||||||
pathname === '/main/game/berrydash/leaderboards')) &&
|
|
||||||
category == Number(key)
|
category == Number(key)
|
||||||
? 'active'
|
? 'active'
|
||||||
: ''
|
: ''
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
export const GetIconForUser = (user: number) => {
|
|
||||||
if (user == 1) return -1
|
|
||||||
else if (user == 2) return -2
|
|
||||||
else if (user == 4) return -3
|
|
||||||
else if (user == 3) return -4
|
|
||||||
else return 1
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user