From 01c87029346b5d93ab3a7285486d9d3e308c7705 Mon Sep 17 00:00:00 2001 From: eatmyvenom Date: Wed, 24 Aug 2022 14:44:37 -0700 Subject: [PATCH 1/5] feat(hypixel-api): create hypixel api client --- .vscode/launch.json | 9 + packages/hypixel-api-client/package.json | 15 ++ packages/hypixel-api-client/src/index.ts | 183 ++++++++++++++++++ .../src/types/base-hypixel-response.d.ts | 11 ++ .../hypixel-api-client/src/types/index.ts | 10 + .../hypixel-api-client/src/types/player.d.ts | 115 +++++++++++ .../hypixel-api-client/src/types/ranks.d.ts | 24 +++ packages/hypixel-api-client/tsconfig.json | 4 + 8 files changed, 371 insertions(+) create mode 100644 packages/hypixel-api-client/package.json create mode 100644 packages/hypixel-api-client/src/index.ts create mode 100644 packages/hypixel-api-client/src/types/base-hypixel-response.d.ts create mode 100644 packages/hypixel-api-client/src/types/index.ts create mode 100644 packages/hypixel-api-client/src/types/player.d.ts create mode 100644 packages/hypixel-api-client/src/types/ranks.d.ts create mode 100644 packages/hypixel-api-client/tsconfig.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 0daf16a13..1d5c0dc0b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,6 +48,15 @@ "cwd": "${workspaceFolder}", "runtimeArgs": ["verify-server", "start"], "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "Prod API", + "runtimeExecutable": "yarn", + "cwd": "${workspaceFolder}", + "runtimeArgs": ["api", "prod-start"], + "outputCapture": "std" } ] } diff --git a/packages/hypixel-api-client/package.json b/packages/hypixel-api-client/package.json new file mode 100644 index 000000000..725fd6044 --- /dev/null +++ b/packages/hypixel-api-client/package.json @@ -0,0 +1,15 @@ +{ + "name": "@statsify/hypixel-api-client", + "version": "0.0.0", + "main": "dist/index.js", + "types": "src/index.ts", + "scripts": { + "build": "swc src --config-file ../../.swcrc --out-dir dist", + "test:types": "tsc --noEmit", + "lint": "TIMING=1 eslint './{src,tests}/**/*.{ts,tsx,js,jsx}' --fix" + }, + "dependencies": { + "@statsify/util": "workspace:^", + "axios": "^0.27.2" + } +} diff --git a/packages/hypixel-api-client/src/index.ts b/packages/hypixel-api-client/src/index.ts new file mode 100644 index 000000000..8cadf75eb --- /dev/null +++ b/packages/hypixel-api-client/src/index.ts @@ -0,0 +1,183 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +import Axios, { AxiosError, AxiosInstance } from "axios"; +import { HypixelPlayer } from "./types"; +import { setTimeout } from "node:timers/promises"; + +export class HypixelKeyRejectedError extends Error { + public constructor(message: string) { + super(message); + this.name = "EHYAPIKEY"; + } +} + +export class HypixelAPIError extends Error { + public constructor(message: string) { + super(message); + this.name = "EHYAPI"; + } +} + +export type HypixelAPIConfig = { + key: string; + autoSleep: boolean; +}; + +export class HypixelAPI { + public limit: number; + public remaining: number; + + private axios: AxiosInstance; + private config: HypixelAPIConfig; + + public constructor(config: HypixelAPIConfig) { + this.axios = Axios.create({ + baseURL: "https://api.hypixel.net/", + headers: { "API-KEY": config.key }, + }); + this.config = config; + } + + public player(uuid: string): Promise { + return this.get("player", { uuid }); + } + + public friends(uuid: string) { + return this.get("friends", { uuid }); + } + + public recentgames(uuid: string) { + return this.get("recentgames", { uuid }); + } + + public status(uuid: string) { + return this.get("status", { uuid }); + } + + public guild(params: { id?: string; player?: string; name?: string }) { + return this.get("guild", params); + } + + public boosters() { + return this.get("boosters"); + } + + public counts() { + return this.get("counts"); + } + + public leaderboards() { + return this.get("leaderboards"); + } + + public punishmentstats() { + return this.get("punishmentstats"); + } + + public skyblockNews() { + return this.get("skyblock/news"); + } + + public skyblockAuction(params: { uuid?: string; player?: string; profile?: string }) { + return this.get("skyblock/auction", params); + } + + public skyblockAuctions(page: number) { + return this.get("skyblock/auctions", { page: `${page}` }); + } + + public skyblockAuctionsEnded() { + return this.get("skyblock/auctions_ended"); + } + + public skyblockBazaar() { + return this.get("skyblock/bazaar"); + } + + public skyblockProfile(profile: string) { + return this.get("skyblock/profile", { profile }); + } + + public skyblockProfiles(uuid: string) { + return this.get("skyblock/profiles", { uuid }); + } + + public skyblockBingo(uuid: string) { + return this.get("skyblock/bingo", { uuid }); + } + + public skyblockFiresales() { + return this.get("skyblock/firesales"); + } + + public async getResource( + resource: + | "games" + | "achievements" + | "challenges" + | "quests" + | "guilds/achievements" + | "vanity/pets" + | "vanity/companions" + | "skyblock/collections" + | "skyblock/skills" + | "skyblock/items" + | "skyblock/election" + | "skyblock/bingo" + ) { + const response = await Axios.get(resource, { + baseURL: "https://api.hypixel.net/resources/", + }); + return response.data; + } + + private async get( + endpoint: string, + params?: Record + ): Promise { + try { + const response = await this.axios.get(endpoint, { params }); + + this.limit = Number(response.headers["rateLimit-limit"]); + this.remaining = Number(response.headers["rateLimit-remaining"]); + + return response.data; + } catch (error: any) { + switch (error.code) { + case 429: { + if (this.config.autoSleep) { + await setTimeout( + Number((error as AxiosError)?.response?.headers?.["retry-after"] ?? 60) * + 1000 + ); + return await this.get(endpoint, params); + } else { + throw error; + } + } + + case 403: { + throw new HypixelKeyRejectedError( + `Hypixel API key "${this.config.key}" was rejected!` + ); + } + + case 500: { + throw new HypixelAPIError( + "The Hypixel API has encountered an error with our request!" + ); + } + + default: { + throw error; + } + } + } + } +} diff --git a/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts b/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts new file mode 100644 index 000000000..10aa145ea --- /dev/null +++ b/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +export declare class BaseHypixelResponse { + public success: boolean; +} diff --git a/packages/hypixel-api-client/src/types/index.ts b/packages/hypixel-api-client/src/types/index.ts new file mode 100644 index 000000000..7bab72495 --- /dev/null +++ b/packages/hypixel-api-client/src/types/index.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +export * from "./base-hypixel-response"; +export * from "./player"; diff --git a/packages/hypixel-api-client/src/types/player.d.ts b/packages/hypixel-api-client/src/types/player.d.ts new file mode 100644 index 000000000..dd19de5f9 --- /dev/null +++ b/packages/hypixel-api-client/src/types/player.d.ts @@ -0,0 +1,115 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +import { BaseHypixelResponse } from "./base-hypixel-response"; +import { HypixelNormalRanks } from "./ranks"; + +declare class HypixelPlayerStats { + public SkyWars?: { [key: string]: any }; + public HungerGames?: { [key: string]: any }; + public Walls?: { [key: string]: any }; + public BattleGround?: { [key: string]: any }; + public UHC?: { [key: string]: any }; + public Walls3?: { [key: string]: any }; + public Arcade?: { [key: string]: any }; + public Quake?: { [key: string]: any }; + public SpeedUHC?: { [key: string]: any }; + public TNTGames?: { [key: string]: any }; + public Arena?: { [key: string]: any }; + public Paintball?: { [key: string]: any }; + public MCGO?: { [key: string]: any }; + public VampireZ?: { [key: string]: any }; + public GingerBread?: { [key: string]: any }; + public SuperSmash?: { [key: string]: any }; + public TrueCombat?: { [key: string]: any }; + public SkyClash?: { [key: string]: any }; + public Bedwars?: { [key: string]: any }; + public Duels?: { [key: string]: any }; + public MurderMystery?: { [key: string]: any }; + public BuildBattle?: { [key: string]: any }; + public Legacy?: { [key: string]: any }; + public Pit?: { [key: string]: any }; + public Housing?: { [key: string]: any }; + public WoolGames?: { [key: string]: any }; +} + +export declare class HypixelPlayerChallenges { + [key: string]: number; +} + +export declare class HypixelPlayerQuest { + public completions?: { time: number }[]; + public active?: { + started?: number; + objectives?: { [key: string]: number }; + }; +} + +export declare class HypixelPlayer extends BaseHypixelResponse { + [key: string]: any; + + /** + * The mongo ID of the player in hypixel + */ + public _id?: string; + + /** + * The players UUID + */ + public uuid?: string; + + /** + * The timestamp of the players first login to hypixel + */ + public firstLogin?: number; + + /** + * The name of the player all lowercase + */ + public playername?: string; + + /** + * The name of the player + */ + public displayname?: string; + + /** + * Known previous names of the player + */ + public knownAliases?: string[]; + + /** + * Known previous names of the player all lowercased + */ + public knownAliasesLower?: string[]; + + public achievementsOneTime?: string[]; + public networkExp?: number; + public karma?: number; + public stats?: HypixelPlayerStats; + public achievements?: Record; + public newPackageRank?: HypixelNormalRanks; + public totalRewards?: number; + public totalDailyRewards?: number; + public rewardStreak?: number; + public rewardScore?: number; + public rewardHighScore?: number; + public achievementPoints?: number; + public challenges?: { + [key: string]: Record; + all_time?: Record; + }; + public quests?: Record; + public parkourCheckpointBests?: { [key: string]: number[] }; + public parkourCompletions?: { + [key: string]: { timeStart?: number; timeTook?: number }[]; + }; + public rankPlusColor?: string; + public monthlyPackageRank?: "NONE" | "SUPERSTAR"; + public monthlyRankColor?: "GOLD" | "AQUA"; +} diff --git a/packages/hypixel-api-client/src/types/ranks.d.ts b/packages/hypixel-api-client/src/types/ranks.d.ts new file mode 100644 index 000000000..afddf69a5 --- /dev/null +++ b/packages/hypixel-api-client/src/types/ranks.d.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +export enum HypixelNormalRanks { + "NONE", + "NORMAL", + "VIP", + "VIP_PLUS", + "MVP", + "MVP_PLUS", +} + +export enum HypixelSpecialRanks { + "YOUTUBER", + "ADMIN", + "GAME_MASTER", +} + +export type HypixelRanks = HypixelNormalRanks | HypixelSpecialRanks; diff --git a/packages/hypixel-api-client/tsconfig.json b/packages/hypixel-api-client/tsconfig.json new file mode 100644 index 000000000..564a59900 --- /dev/null +++ b/packages/hypixel-api-client/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"] +} From 372fc114f19a5ea0f606a450da03e29353a03392 Mon Sep 17 00:00:00 2001 From: eatmyvenom Date: Thu, 6 Oct 2022 14:59:49 -0700 Subject: [PATCH 2/5] feat(hypixel-api): improve types --- packages/hypixel-api-client/src/index.ts | 6 +- .../hypixel-api-client/src/types/APIData.d.ts | 9 ++ .../hypixel-api-client/src/types/games.d.ts | 114 ++++++++++++++++++ .../hypixel-api-client/src/types/player.d.ts | 62 +++------- 4 files changed, 144 insertions(+), 47 deletions(-) create mode 100644 packages/hypixel-api-client/src/types/APIData.d.ts create mode 100644 packages/hypixel-api-client/src/types/games.d.ts diff --git a/packages/hypixel-api-client/src/index.ts b/packages/hypixel-api-client/src/index.ts index 8cadf75eb..b53602025 100644 --- a/packages/hypixel-api-client/src/index.ts +++ b/packages/hypixel-api-client/src/index.ts @@ -7,7 +7,7 @@ */ import Axios, { AxiosError, AxiosInstance } from "axios"; -import { HypixelPlayer } from "./types"; +import { HypixelPlayerResponse } from "./types"; import { setTimeout } from "node:timers/promises"; export class HypixelKeyRejectedError extends Error { @@ -44,8 +44,8 @@ export class HypixelAPI { this.config = config; } - public player(uuid: string): Promise { - return this.get("player", { uuid }); + public player(uuid: string): Promise { + return this.get("player", { uuid }); } public friends(uuid: string) { diff --git a/packages/hypixel-api-client/src/types/APIData.d.ts b/packages/hypixel-api-client/src/types/APIData.d.ts new file mode 100644 index 000000000..f198d4d93 --- /dev/null +++ b/packages/hypixel-api-client/src/types/APIData.d.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +export type APIData = Record; diff --git a/packages/hypixel-api-client/src/types/games.d.ts b/packages/hypixel-api-client/src/types/games.d.ts new file mode 100644 index 000000000..5485ce7d9 --- /dev/null +++ b/packages/hypixel-api-client/src/types/games.d.ts @@ -0,0 +1,114 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +export type HypixelLobby = + | "Adventure" + | "ArcadeGames" + | "Arena" + | "Bedwars" + | "BlitzLobby" + | "BuildBattle" + | "CopsnCrims" + | "Duels" + | "Housing" + | "Legacy" + | "MainLobby" + | "MegaWalls" + | "MurderMystery" + | "NewMainLobby" + | "Paintball" + | "Prototype" + | "QuakeCraft" + | "SC" + | "SkyClash" + | "Skywars" + | "SkywarsAug2017" + | "SkywarsChristmas2017" + | "SkywarsStandard2022" + | "SpeedUHC" + | "SuperSmash" + | "TNT" + | "TheWallsLobby" + | "Tourney" + | "TruePVPParkour" + | "Turbo" + | "Warlords" + | "WoolGames" + | "blitz" + | "bossfight" + | "christmas" + | "main" + | "mainLobby2017" + | "mainLobby2022" + | "megawallslobby" + | "newwalls" + | "overhaul" + | "quakelobby" + | "uhc" + | "vampirez"; + +export type HypixelGameMode = + | "Arcade" + | "Arena" + | "Battleground" + | "Bedwars" + | "BuildBattle" + | "Duels" + | "GingerBread" + | "Housing" + | "HungerGames" + | "Legacy" + | "MCGO" + | "MurderMystery" + | "Paintball" + | "Pit" + | "Quake" + | "SkyClash" + | "SkyWars" + | "SpeedUHC" + | "SuperSmash" + | "TNTGames" + | "TrueCombat" + | "UHC" + | "VampireZ" + | "Walls" + | "Walls3" + | "WoolGames"; + +export type HypixelAchievementMode = + | "arcade" + | "arena" + | "bedwars" + | "blitz" + | "buildbattle" + | "christmas2017" + | "copsandcrims" + | "duels" + | "easter" + | "general" + | "gingerbread" + | "halloween2017" + | "housing" + | "murdermystery" + | "paintball" + | "pit" + | "quake" + | "skyblock" + | "skyclash" + | "skywars" + | "speeduhc" + | "summer" + | "supersmash" + | "tntgames" + | "truecombat" + | "uhc" + | "vampirez" + | "walls" + | "walls3" + | "warlords" + | "woolgames"; diff --git a/packages/hypixel-api-client/src/types/player.d.ts b/packages/hypixel-api-client/src/types/player.d.ts index dd19de5f9..91ba51dd9 100644 --- a/packages/hypixel-api-client/src/types/player.d.ts +++ b/packages/hypixel-api-client/src/types/player.d.ts @@ -6,40 +6,20 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ +import { APIData } from "./APIData"; import { BaseHypixelResponse } from "./base-hypixel-response"; +import { HypixelAchievementMode, HypixelGameMode, HypixelLobby } from "./games"; import { HypixelNormalRanks } from "./ranks"; +export type ChallengesTime = `day_${string}` | "all__time"; +export type AchievementName = `${HypixelAchievementMode}_${string}`; + declare class HypixelPlayerStats { - public SkyWars?: { [key: string]: any }; - public HungerGames?: { [key: string]: any }; - public Walls?: { [key: string]: any }; - public BattleGround?: { [key: string]: any }; - public UHC?: { [key: string]: any }; - public Walls3?: { [key: string]: any }; - public Arcade?: { [key: string]: any }; - public Quake?: { [key: string]: any }; - public SpeedUHC?: { [key: string]: any }; - public TNTGames?: { [key: string]: any }; - public Arena?: { [key: string]: any }; - public Paintball?: { [key: string]: any }; - public MCGO?: { [key: string]: any }; - public VampireZ?: { [key: string]: any }; - public GingerBread?: { [key: string]: any }; - public SuperSmash?: { [key: string]: any }; - public TrueCombat?: { [key: string]: any }; - public SkyClash?: { [key: string]: any }; - public Bedwars?: { [key: string]: any }; - public Duels?: { [key: string]: any }; - public MurderMystery?: { [key: string]: any }; - public BuildBattle?: { [key: string]: any }; - public Legacy?: { [key: string]: any }; - public Pit?: { [key: string]: any }; - public Housing?: { [key: string]: any }; - public WoolGames?: { [key: string]: any }; + [key: HypixelGameMode]: APIData; } export declare class HypixelPlayerChallenges { - [key: string]: number; + [key: `${Uppercase}_${string}`]: number; } export declare class HypixelPlayerQuest { @@ -50,7 +30,7 @@ export declare class HypixelPlayerQuest { }; } -export declare class HypixelPlayer extends BaseHypixelResponse { +export declare class HypixelPlayer { [key: string]: any; /** @@ -78,21 +58,11 @@ export declare class HypixelPlayer extends BaseHypixelResponse { */ public displayname?: string; - /** - * Known previous names of the player - */ - public knownAliases?: string[]; - - /** - * Known previous names of the player all lowercased - */ - public knownAliasesLower?: string[]; - - public achievementsOneTime?: string[]; + public achievementsOneTime?: AchievementName[]; public networkExp?: number; public karma?: number; public stats?: HypixelPlayerStats; - public achievements?: Record; + public achievements?: Record; public newPackageRank?: HypixelNormalRanks; public totalRewards?: number; public totalDailyRewards?: number; @@ -101,15 +71,19 @@ export declare class HypixelPlayer extends BaseHypixelResponse { public rewardHighScore?: number; public achievementPoints?: number; public challenges?: { - [key: string]: Record; - all_time?: Record; + [key: ChallengesTime]: HypixelPlayerChallenges; + all_time?: HypixelPlayerChallenges; }; public quests?: Record; - public parkourCheckpointBests?: { [key: string]: number[] }; + public parkourCheckpointBests?: { [key: HypixelLobby]: number[] }; public parkourCompletions?: { - [key: string]: { timeStart?: number; timeTook?: number }[]; + [key: HypixelLobby]: { timeStart?: number; timeTook?: number }[]; }; public rankPlusColor?: string; public monthlyPackageRank?: "NONE" | "SUPERSTAR"; public monthlyRankColor?: "GOLD" | "AQUA"; } + +export declare class HypixelPlayerResponse extends BaseHypixelResponse { + public player: HypixelPlayer; +} From a3612de2f4882dd690833d9e482cff180595c402 Mon Sep 17 00:00:00 2001 From: eatmyvenom Date: Tue, 1 Nov 2022 22:43:19 -0700 Subject: [PATCH 3/5] feat(hypixel-api): super strong types --- packages/hypixel-api-client/src/index.ts | 2 + .../hypixel-api-client/src/types/helpers.d.ts | 40 ++ .../hypixel-api-client/src/types/index.ts | 3 + .../src/types/player-stats.d.ts | 18 + .../hypixel-api-client/src/types/player.d.ts | 44 +- .../hypixel-api-client/src/types/ranks.d.ts | 1 + .../types/{APIData.d.ts => stats/index.ts} | 2 +- .../src/types/stats/pit-stats.d.ts | 658 ++++++++++++++++++ packages/schemas/package.json | 1 + .../schemas/src/player/gamemodes/pit/index.ts | 13 +- .../schemas/src/player/gamemodes/pit/util.ts | 10 +- packages/schemas/src/player/index.ts | 4 +- packages/schemas/src/player/stats.ts | 18 +- yarn.lock | 10 + 14 files changed, 793 insertions(+), 31 deletions(-) create mode 100644 packages/hypixel-api-client/src/types/helpers.d.ts create mode 100644 packages/hypixel-api-client/src/types/player-stats.d.ts rename packages/hypixel-api-client/src/types/{APIData.d.ts => stats/index.ts} (84%) create mode 100644 packages/hypixel-api-client/src/types/stats/pit-stats.d.ts diff --git a/packages/hypixel-api-client/src/index.ts b/packages/hypixel-api-client/src/index.ts index b53602025..bc42cb847 100644 --- a/packages/hypixel-api-client/src/index.ts +++ b/packages/hypixel-api-client/src/index.ts @@ -181,3 +181,5 @@ export class HypixelAPI { } } } + +export * from "./types"; diff --git a/packages/hypixel-api-client/src/types/helpers.d.ts b/packages/hypixel-api-client/src/types/helpers.d.ts new file mode 100644 index 000000000..ec22e3e45 --- /dev/null +++ b/packages/hypixel-api-client/src/types/helpers.d.ts @@ -0,0 +1,40 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +type PrependNextNum> = A["length"] extends infer T + ? ((t: T, ...a: A) => void) extends (...x: infer X) => void + ? X + : never + : never; + +type EnumerateInternal, N extends number> = { + 0: A; + 1: EnumerateInternal, N>; +}[N extends A["length"] ? 0 : 1]; + +export type Enumerate = EnumerateInternal<[], N> extends (infer E)[] + ? E + : never; + +export type IntRange = Exclude< + Enumerate, + Enumerate +>; + +interface BasicStats { + [key: string]: any; + coins?: number; + lastTourneyAd?: number; +} + +interface NBTData { + type: number; + data: ArrayBuffer; +} + +export type APIData = Record; diff --git a/packages/hypixel-api-client/src/types/index.ts b/packages/hypixel-api-client/src/types/index.ts index 7bab72495..485f14ebe 100644 --- a/packages/hypixel-api-client/src/types/index.ts +++ b/packages/hypixel-api-client/src/types/index.ts @@ -8,3 +8,6 @@ export * from "./base-hypixel-response"; export * from "./player"; +export * from "./player-stats"; +export * from "./stats"; +export * from "./helpers"; diff --git a/packages/hypixel-api-client/src/types/player-stats.d.ts b/packages/hypixel-api-client/src/types/player-stats.d.ts new file mode 100644 index 000000000..279d4aa92 --- /dev/null +++ b/packages/hypixel-api-client/src/types/player-stats.d.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +import type { APIData, BasicStats } from "./helpers"; +import type { HypixelPitStats } from "./stats"; + +interface IHypixelStats { + [key: HypixelGameMode]: BasicStats; + Pit: HypixelPitStats; +} + +export type HypixelPlayerStats = Record & + IHypixelStats; diff --git a/packages/hypixel-api-client/src/types/player.d.ts b/packages/hypixel-api-client/src/types/player.d.ts index 91ba51dd9..b7dea15ae 100644 --- a/packages/hypixel-api-client/src/types/player.d.ts +++ b/packages/hypixel-api-client/src/types/player.d.ts @@ -6,18 +6,14 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -import { APIData } from "./APIData"; import { BaseHypixelResponse } from "./base-hypixel-response"; import { HypixelAchievementMode, HypixelGameMode, HypixelLobby } from "./games"; import { HypixelNormalRanks } from "./ranks"; +import { HypixelPlayerStats } from "./player-stats"; export type ChallengesTime = `day_${string}` | "all__time"; export type AchievementName = `${HypixelAchievementMode}_${string}`; -declare class HypixelPlayerStats { - [key: HypixelGameMode]: APIData; -} - export declare class HypixelPlayerChallenges { [key: `${Uppercase}_${string}`]: number; } @@ -30,7 +26,20 @@ export declare class HypixelPlayerQuest { }; } -export declare class HypixelPlayer { +export declare class HypixelPlayer_Settings { + public fishCollectorShowCaught?: boolean; +} + +export declare class HypixelPlayerSeasonal { + [key: "halloween" | "summer"]: { "2022"?: { levelling?: { experience: number } } }; + public silver: number; +} + +export type HypixelPlayerAchievementRewardsNew = { + [key: `for_points_${number}00`]: number; +}; + +export declare class HypixelPlayer { [key: string]: any; /** @@ -38,10 +47,12 @@ export declare class HypixelPlayer { */ public _id?: string; + public _settings?: HypixelPlayer_Settings; + /** * The players UUID */ - public uuid?: string; + public uuid: string; /** * The timestamp of the players first login to hypixel @@ -51,17 +62,29 @@ export declare class HypixelPlayer { /** * The name of the player all lowercase */ - public playername?: string; + public playername?: Lowercase; /** * The name of the player */ - public displayname?: string; + public displayname: PName; public achievementsOneTime?: AchievementName[]; + public achievementRewardsNew?: HypixelPlayerAchievementRewardsNew; public networkExp?: number; public karma?: number; public stats?: HypixelPlayerStats; + public socialMedia?: { + links: { + DISCORD?: string; + HYPIXEL?: string; + INSTAGRAM?: string; + MIXER?: string; + TWITCH?: string; + TWITTER?: string; + YOUTUBE?: string; + }; + }; public achievements?: Record; public newPackageRank?: HypixelNormalRanks; public totalRewards?: number; @@ -70,6 +93,9 @@ export declare class HypixelPlayer { public rewardScore?: number; public rewardHighScore?: number; public achievementPoints?: number; + public battlePassGlowStatus?: boolean; + public firstLogin?: number; + public seasonal?: HypixelPlayerSeasonal; public challenges?: { [key: ChallengesTime]: HypixelPlayerChallenges; all_time?: HypixelPlayerChallenges; diff --git a/packages/hypixel-api-client/src/types/ranks.d.ts b/packages/hypixel-api-client/src/types/ranks.d.ts index afddf69a5..f6ff51e39 100644 --- a/packages/hypixel-api-client/src/types/ranks.d.ts +++ b/packages/hypixel-api-client/src/types/ranks.d.ts @@ -19,6 +19,7 @@ export enum HypixelSpecialRanks { "YOUTUBER", "ADMIN", "GAME_MASTER", + "OWNER", } export type HypixelRanks = HypixelNormalRanks | HypixelSpecialRanks; diff --git a/packages/hypixel-api-client/src/types/APIData.d.ts b/packages/hypixel-api-client/src/types/stats/index.ts similarity index 84% rename from packages/hypixel-api-client/src/types/APIData.d.ts rename to packages/hypixel-api-client/src/types/stats/index.ts index f198d4d93..a14f8606a 100644 --- a/packages/hypixel-api-client/src/types/APIData.d.ts +++ b/packages/hypixel-api-client/src/types/stats/index.ts @@ -6,4 +6,4 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -export type APIData = Record; +export * from "./pit-stats"; diff --git a/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts b/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts new file mode 100644 index 000000000..4c9c505c7 --- /dev/null +++ b/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts @@ -0,0 +1,658 @@ +/** + * Copyright (c) Statsify + * + * This source code is licensed under the GNU GPL v3 license found in the + * LICENSE file in the root directory of this source tree. + * https://github.com/Statsify/statsify/blob/main/LICENSE + */ + +import { BasicStats, IntRange, NBTData } from "../helpers"; + +export enum HypixelPitGenesisFactions { + angel = "angel", + demon = "demon", +} + +export interface HypixelPitContract { + /** + * either EASY or HARD, representing a Novice or Big Time contract respectively. + */ + difficulty: "EASY" | "HARD"; + + /** + * Amount of gold the player earned from completing the contract. + */ + gold_reward: number; + + /** + * Object. Contains a key representing the objective the player needs to complete for the contract. + */ + requirements: Record; + + /** + * Object. Contains a key representing the progress the player has already made in the contract. + */ + progress: Record; + + /** + * The number of Chunks of Vile the player will receive if they complete the contract. + */ + chunk_of_viles_reward: number; + + completion_date: 0; + + /** + * How many ticks are left in the contract's 5-minute timer. One tick is equal to 0.05 seconds. + */ + remaining_ticks: number; + + /** + * Description of the contract's objective. + */ + key: string; +} + +export interface HypixelPitBounty { + /** + * The gold amount of the bounty bump + */ + amount: number; + + /** + * @deprecated Does not count down and is always an unreasonably high number + */ + remainingTicks: number; + + /** + * The Unix timestamp of when the player received the bounty + */ + timestamp: number; +} + +interface HypixelPitShopsThrottle { + [key: `${"buyer_" | ""}${"Hay" | "Bread" | "Fish"}`]: { + /** + * The latest date the player sold items to that NPC. + */ + lastEpochDay: number; + + /** + * The number of items that were sold on `lastEpochDay`. + */ + count: number; + }; +} + +export interface HypixelPitStatsPTL { + assists: number; + cash_earned: number; + damage_dealt: number; + damage_received: number; + deaths: number; + gapple_eaten: number; + joins: number; + jumped_into_pit: number; + kills: number; + left_clicks: number; + max_streak: number; + melee_damage_dealt: number; + melee_damage_received: number; + playtime_minutes: number; + sword_hits: number; + arrow_hits: number; + arrows_fired: number; + bow_damage_dealt: number; + bow_damage_received: number; + ghead_eaten: number; + launched_by_launchers: number; + contracts_completed: number; + contracts_started: number; + fishing_rod_launched: number; + chat_messages: number; + diamond_items_purchased: number; + enderchest_opened: number; + fished_anything: number; + wheat_farmed: number; + sewer_treasures_found: number; + blocks_placed: number; + blocks_broken: number; + king_quest_completion: number; + lava_bucket_emptied: number; + + /** + * Gold earned from picking up ingots. + */ + ingots_cash: number; + + /** + * Total number of gold ingots picked up. + */ + ingots_picked_up: number; + + /** + * Total amount of HP healed with the Vampire perk. + */ + vampire_healed_hp: number; + + /** + * Total number of Rage Potatoes eaten from the Rage Pit event. + */ + rage_potatoes_eaten: number; + + enchanted_tier1: number; + enchanted_tier2: number; + enchanted_tier3: number; + + soups_drank: number; + night_quests_completed: number; + obsidian_broken: number; + + /** + * Number of diamond armor pieces obtained from the Lucky Diamond perk. + */ + lucky_diamond_pieces: number; + + /** + * Number of arrows earned from the Spammer perk. + */ + endless_quiver_arrows: number; + + /** + * Amount of gold earned from the Trickle Down perk. + */ + extra_from_trickle_down: number; + + /** + * Number of bounties worth 500g or greater claimed with the Bounty Hunter perk. + */ + bounties_of_500g_with_bh: number; + + fishes_fished: number; + rambo_kills: number; + launched_by_angel_spawn: number; + launched_by_demon_spawn: number; + rage_pants_crafted: number; + gold_from_farming: number; + dark_pants_crated: number; + dark_pants_t2: number; + hidden_jewel_triggers: number; + gold_from_selling_fish: number; +} + +export interface HypixelPitOutgoingOffer { + /** + * Unix timestamp of when the command was sent. + */ + issued_ms: number; + + /** + * The price, in gold, the recipient will need to pay to receive the item. + */ + gold: number; + + /** + * Object. Contains a byte array of the object being sent. + */ + item: NBTData; + + /** + * Unknown use; seemingly always −1, regardless whether the item is pants or not. + */ + pants: -1; + + /** + * UUID of the trade. Can be used in the /inspectoffer [uuid] command to open the offer GUI without needing to click. + */ + uuid: string; + + /** + * Unknown use; seemingly always 0, regardless of how many pants are included in the offer. + */ + pants_count: 0; + + /** + * UUID of the recipient. + */ + target: string; +} + +export interface HypixelPitKingsQuest { + kills: number; + renown: number; + last_completed: number; + last_accepted: number; +} + +export interface HypixelPitUnlocks { + tier: number; + acquireDate: number; + key: string; +} + +export interface HypixelPitPrestiges { + index: IntRange<1, 50>; + xp_on_prestige: number; + timestamp: number; +} + +export interface HypixelPitRenownUnlocks { + tier: number; + acquireDate: number; + key: string; +} + +export enum HypixelPitChatOptions { + "kill_feed", + "prestige_announcements", + "minor_events", + "streaks", + "player_chat", + "bounties", + "misc", +} + +export type IHypixelPitProfile = { + // + // All index types are here for use with iteration, + // these are also all added as records to the actual type + // + + /** + * List of upgrades (perks, passives, and killstreaks) that the player unlocked at each prestige. + * Each unlock contains a "tier" (set to 0 if the upgrade has no tier), Unix timestamp, and a key. + * The player's first prestige is stored as unlocks, not unlocks_0. + */ + [unlocksIndex: `unlocks${"" | `_${number}`}`]: HypixelPitUnlocks; + + /** + * The player's selected perks. + */ + [perk: `selected_perk_${number}`]: string; + + /** + * The amount of gold the player obtained during a prestige. + */ + [key: `cash_during_prestige_${number}`]: number; + + /** + * The player's /pitchat settings. + */ + [chatOption: `chat_option_${keyof typeof HypixelPitChatOptions}`]: boolean; + + /** + * Unix timestamps of when the player last claimed various faction items and perks. + */ + [ + genesisClaims: `genesis_weekly_perks_${ + | `perma_${"xp" | "gold"}` + | `claim_item_${HypixelPitGenesisFactions}`}` + ]: number; + + /** + * The number of times the player has claimed the Tier VII reward of the respective faction. + */ + [genesisPerma: `genesis_perma_${HypixelPitGenesisFactions}`]: number; + + /** + * The player's selected killstreaks. + */ + [killstreak: `selected_killstreak_${number}`]: string; + [stackStreaks: `${"gold" | "xp"}_stack_streak_${number}`]: number; + + xp: number; + cash: number; + renown: number; + + /** + * The current outgoing offers the player has,created with /offer. The objects, each corresponding to one use of the /offer command, contain several keys. + */ + outgoing_offers: HypixelPitOutgoingOffer[]; + + /** + * The Unix timestamp of the player's most recent save of their API stats. Updates to the current + * time approximately every three minutes when the player is in Pit. Does not update when it has + * been more than three minutes since the player played Pit. + */ + last_save: number; + + /** + * Stats for the most recent King's Quest the player started. + */ + king_quest: HypixelPitKingsQuest; + + /** + * Unix timestamp of when the player last received participation XP. + */ + last_passive_xp: number; + + /** + * ??? + */ + trade_timestamps: []; + + /** + * Byte array of the contents of the player's ender chest. + */ + inv_enderchest: NBTData; + + /** + * Byte arrays of the player's four most recent death recaps. Formatting codes are included in the array. + */ + death_recaps: NBTData; + + /** + * Whether the player has selected to spawn in their faction's base. + */ + genesis_spawn_in_base: boolean; + + /** + * The player's statistics for the in-game Pit leaderboards. + */ + leaderboard_stats: Record< + `Pit_${ + | "blockhead_blocks" + | `tdm_${"red" | "blue"}_kills` + | `kotl_${"time" | "gold"}` + | "rage_pit_damage" + | "kills_as_beast" + | `raffle_${"tickets" | "jackpot"}` + | "auction_bid" + | "cake_eaten"}_20${IntRange<19, 24>}_${"fall" | "winter" | "summer" | "spring"}`, + number + >; + + /** + * The player's currently in-progress contract. + */ + contract: HypixelPitContract; + + /** + * Unix timestamp of the player's last completed contract. + */ + last_contract: number; + + /** + * The player's most recently completed trades. + */ + gold_transactions: { + amount: number; + timestamp: number; + }[]; + + /** + * The player's most recently-chosen faction on the Genesis map. + */ + genesis_allegiance: Uppercase; + + /** + * The player's inventory contents. Stored as a byte array. + */ + inv_contents: NBTData; + + /** + * Unix timestamps of when the player last purchased each item in the item shop. + */ + items_last_buy: { + "Pants Bundle": number; + bounty_solvent: number; + combat_spade: number; + diamond_boots: number; + diamond_chestplate: number; + diamond_leggings: number; + diamond_sword: number; + first_aid_egg: number; + golden_pickaxe: number; + iron_pack: number; + jump_boost_potion: number; + new_golden_pickaxe: number; + obsidian: number; + obsidian_stack: number; + tactical_insertion: number; + }; + + /** + * Faction points earned on the most recent iteration of the Genesis map. + */ + genesis_points: number; + + /** + * Array of prestiges. + */ + prestiges: HypixelPitPrestiges[]; + + /** + * Byte array of the player's Spire stash inventory, containing the player's items that will be given + * back to them once the Spire event concludes. + */ + spire_stash_inv: NBTData; + + /** + * Byte array of the player's Spire stash armor, containing the player's armor that will be given + * back to them once the Spire event concludes. + */ + spire_stash_armor: NBTData; + + cheap_milk: false; + + /** + * Whether the player has logged in at least once after March 19th, 2018, the date of The Pit 0.3's release. + */ + zero_point_three_gold_transfer: boolean; + + /** + * Contains several objects, each corresponding to a renown unlock. + */ + renown_unlocks: HypixelPitRenownUnlocks[]; + + /** + * Unix timestamp of the last time the player disconnected while in combat. + */ + last_midfight_disconnect: number; + + inv_armor: NBTData; + + item_stash: NBTData; + + /** + * Unix timestamp of when the player last selected a faction to join. + */ + genesis_allegiance_time: number; + + /** + * ??? + */ + login_messages: any[]; + + /** + * Array of Minecraft Item IDs corresponding to inventory slots. + * Slots represent the locations items respawn in when the player dies. + */ + hotbar_favorites: [ + number, + number, + number, + number, + number, + number, + number, + number, + number + ]; + + ended_contracts: HypixelPitContract[]; + + /** + * List of bounty bumps + */ + bounties: HypixelPitBounty[]; + + /** + * Whether the player chooses to receive Night Quests. + */ + night_quests_enabled: boolean; + + /** + * The leaderboard that displays for the player in spawn. + */ + selected_leaderboard: string; + + /** + * The player's selected megastreak. Returns null if the megastreak is Overdrive. + */ + selected_killstreak_0: string; + + /** + * Whether the player is choosing to display their Pit Supporter star. + */ + supporter_star_enabled: boolean; + + /** + * Whether the player chose to disable the default sword and bow from their inventory when they spawn. + */ + disable_spawn_items: boolean; + + shops_throttle: HypixelPitShopsThrottle; + + /** + * Array of items that the player has Autobuy enabled on. + */ + autobuy_items: string[]; + + /** + * List of the three contracts the player can select. + * Returns null if the player has no contracts to select + */ + contract_choices: + | [HypixelPitContract?, HypixelPitContract?, HypixelPitContract?] + | null; + + /** + * The player has in their Mystic Well. + */ + mystic_well_item: NBTData; + + /** + * The player's selected megastreak. If they have Uberstreak selected, + * this key returns the player's previously-selected megastreak instead. + */ + selected_megastreak_except_uber: string; + + /** + * Unix timestamps of the player's recent Uberstreak completions. + */ + recent_uberstreaks: number[]; + + /** + * Whether the player's Fancy Hat has an enchanted glint from Pit Supporter. + */ + hat_glint_enabled: boolean; + + /** + * Whether the player has the renown perk Apollo enabled. + */ + apollo_enabled: boolean; + + /** + * Array of events the player helped create in The Pit 0.4. + * Events only appear if the player clicked the "Collect reward" button + * in the Prestige NPC before The Pit 1.0.0. + */ + event_contest_claims: string[]; + + /** + * The stats that the player has the /dropconfirm command in; true for the drop + * confirm being disabled, and false for the drop confirm being enabled. + */ + drop_confirm_disabled: boolean; + + /** + * ??? + */ + zero_point_two_xp: number; + + /** + * Whether the player has the Fancy Hat renown upgrade enabled. + */ + hat_enabled: boolean; + + /** + * Whether the player has the Impatient renown upgrade enabled. + */ + impatient_enabled: boolean; + + /** + * The player's selected launch trail from the renown shop. + */ + selected_launch_trail: string; + + /** + * Whether the player refunded 10 renown from the Golden Pickaxe being + * removed from the renown shop in The Pit 1.0.5. + */ + refunded_golden_pickaxe: boolean; + + /** + * The item in the "sacrifice" slot of the Mystic Well. + */ + mystic_well_pants: NBTData; + + /** + * The Unix time of the player's last use of a Mark of Recon Essence. + */ + reconessence_day: number; + + /** + * The Unix time of when the player last wore dark pants + * with the Lycanthropy enchantment. + */ + last_lycanthropy: number; + + /** + * ??? + */ + uber_paid_up: number; + + /** + * The number of times the player has claimed the +1% + * Mystic Drop Chance Uberdrop from an Uberstreak. + */ + uberdrop_mystic_stacks: number; + + /** + * Whether the player has the renown upgrade Raw Numbers enabled. + */ + raw_numbers_enabled: boolean; + + /** + * @Deprecated + * + * Used by admins to test the contracts feature. + */ + contract_offers: any; +}; + +export type HypixelPitProfile = IHypixelPitProfile & + Record<`unlocks${"" | `_${IntRange<1, 51>}`}`, HypixelPitUnlocks> & + Record<`selected_perk_${IntRange<0, 4>}`, string> & + Record<`cash_during_prestige_${IntRange<0, 50>}`, number> & + Record<`chat_option_${keyof typeof HypixelPitChatOptions}`, boolean> & + Record< + `genesis_weekly_perks_${ + | `perma_${"xp" | "gold"}` + | `claim_item_${keyof typeof HypixelPitGenesisFactions}`}`, + number + > & + Record<`genesis_perma_${keyof typeof HypixelPitGenesisFactions}`, number> & + Record<`selected_killstreak_${IntRange<1, 5>}`, string> & + Record<`${"gold" | "xp"}_stack_streak_${IntRange<0, 51>}`, number> & + Record<`selected_killstreak_${IntRange<1, 5>}`, string>; + +export interface HypixelPitStats extends BasicStats { + packages?: ["supporter"]; + restored_inv_backup_1?: number; + stats_move_1: number; + pit_stats_ptl?: HypixelPitStatsPTL & unknown; + profile?: HypixelPitProfile; +} + +(({} as HypixelPitProfile).selected_perk_1); diff --git a/packages/schemas/package.json b/packages/schemas/package.json index 79d611ac6..e81410655 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@nestjs/swagger": "^6.0.1", + "@statsify/hypixel-api-client": "workspace:^", "@statsify/logger": "workspace:^", "@statsify/math": "workspace:^", "@statsify/util": "workspace:^", diff --git a/packages/schemas/src/player/gamemodes/pit/index.ts b/packages/schemas/src/player/gamemodes/pit/index.ts index ab701b78a..bcf675cc8 100644 --- a/packages/schemas/src/player/gamemodes/pit/index.ts +++ b/packages/schemas/src/player/gamemodes/pit/index.ts @@ -6,18 +6,19 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -import { APIData, formatTime } from "@statsify/util"; import { Field } from "../../../metadata"; -import { GameModes, IGameModes } from "../../../game"; -import { Progression } from "../../../progression"; -import { add, ratio } from "@statsify/math"; -import { getBounty, getLevel, getLevelFormatted, getPres, getPresReq } from "./util"; export const PIT_MODES = new GameModes([ { api: "overall", hypixel: "PIT", formatted: "Pit" }, ]); export type PitModes = IGameModes; +import { GameModes, IGameModes } from "../../../game"; +import { HypixelPitProfile, HypixelPitStatsPTL } from "@statsify/hypixel-api-client"; +import { Progression } from "../../../progression"; +import { add, ratio } from "@statsify/math"; +import { formatTime } from "@statsify/util"; +import { getBounty, getLevel, getLevelFormatted, getPres, getPresReq } from "./util"; export class Pit { @Field({ @@ -105,7 +106,7 @@ export class Pit { @Field() public joins: number; - public constructor(profile: APIData, data: APIData) { + public constructor(profile: HypixelPitProfile, data: HypixelPitStatsPTL) { this.exp = profile.xp ?? 0; this.gold = profile.cash; this.renown = profile.renown; diff --git a/packages/schemas/src/player/gamemodes/pit/util.ts b/packages/schemas/src/player/gamemodes/pit/util.ts index 4b09dd657..ef2a8d8e7 100644 --- a/packages/schemas/src/player/gamemodes/pit/util.ts +++ b/packages/schemas/src/player/gamemodes/pit/util.ts @@ -6,6 +6,7 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ +import { HypixelPitBounty } from "@statsify/hypixel-api-client"; import { romanNumeral } from "@statsify/util"; const xpMap = [15, 30, 50, 75, 125, 300, 600, 800, 900, 1000, 1200, 1500]; @@ -46,13 +47,6 @@ const levelColors = [ "l§b", ]; -export type Bounty = { - amount: number; - remainingTicks: number; - issuer: string; - timestamp: number; -}; - export const getPres = (xp: number) => { for (let i = 0; i < 50; i++) { if (xp <= presXpReq[i]) { @@ -82,7 +76,7 @@ export const getLevelColor = (level: number) => export const getPresColor = (pres: number) => pres == 0 ? prestigecolors[0] : prestigecolors[Math.floor((pres + 5) / 5)]; -export const getBounty = (bounties: Bounty[]) => +export const getBounty = (bounties: HypixelPitBounty[]) => bounties ? bounties.reduce((p, c) => p + c.amount, 0) : 0; export const getLevelFormatted = (level: number, prestige: number) => { diff --git a/packages/schemas/src/player/index.ts b/packages/schemas/src/player/index.ts index f52fcf9f0..4c9d6259a 100644 --- a/packages/schemas/src/player/index.ts +++ b/packages/schemas/src/player/index.ts @@ -6,9 +6,9 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -import { APIData } from "@statsify/util"; import { Color } from "../color"; import { Field } from "../metadata"; +import { HypixelPlayer } from "@statsify/hypixel-api-client"; import { modelOptions as ModelOptions, Severity } from "@typegoose/typegoose"; import { PlayerSocials } from "./socials"; import { PlayerStats } from "./stats"; @@ -82,7 +82,7 @@ export class Player { @Field({ store: { required: false } }) public guildId?: string; - public constructor(data: APIData = {}) { + public constructor(data: HypixelPlayer) { this.uuid = data.uuid; this.username = data.displayname; this.usernameToLower = this.username?.toLowerCase(); diff --git a/packages/schemas/src/player/stats.ts b/packages/schemas/src/player/stats.ts index bdc321f46..7d093df2c 100644 --- a/packages/schemas/src/player/stats.ts +++ b/packages/schemas/src/player/stats.ts @@ -36,7 +36,12 @@ import { } from "./gamemodes"; import { Field } from "../metadata"; import { FormattedGame } from "../game"; -import type { APIData } from "@statsify/util"; +import { + HypixelPitProfile, + HypixelPitStatsPTL, + HypixelPlayer, + HypixelPlayerStats, +} from "@statsify/hypixel-api-client"; export class PlayerStats { @Field({ leaderboard: { fieldName: `${FormattedGame.ARCADE} -` } }) @@ -196,10 +201,10 @@ export class PlayerStats { }) public woolwars: WoolWars; - public constructor(data: APIData = {}) { + public constructor(data: HypixelPlayer) { const achievements = data?.achievements ?? {}; - const stats = data?.stats ?? {}; - const legacy = stats.Legacy ?? {}; + const stats = data?.stats ?? ({} as HypixelPlayerStats); + const legacy = stats?.Legacy ?? {}; this.arcade = new Arcade(stats.Arcade ?? {}, achievements); this.arenabrawl = new ArenaBrawl(stats.Arena ?? {}, legacy); @@ -214,7 +219,10 @@ export class PlayerStats { this.murdermystery = new MurderMystery(stats.MurderMystery ?? {}, achievements); this.paintball = new Paintball(stats.Paintball ?? {}, legacy); this.parkour = new Parkour(data.parkourCompletions ?? {}); - this.pit = new Pit(stats.Pit?.profile ?? {}, stats.Pit?.pit_stats_ptl ?? {}); + this.pit = new Pit( + stats.Pit?.profile ?? ({} as HypixelPitProfile), + stats.Pit?.pit_stats_ptl ?? ({} as HypixelPitStatsPTL) + ); this.quake = new Quake(stats.Quake ?? {}, achievements, legacy); this.quests = new Quests(data.quests ?? {}); this.skywars = new SkyWars(stats.SkyWars ?? {}, achievements); diff --git a/yarn.lock b/yarn.lock index 1f36bf23b..a2220963b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1731,6 +1731,15 @@ __metadata: languageName: unknown linkType: soft +"@statsify/hypixel-api-client@workspace:^, @statsify/hypixel-api-client@workspace:packages/hypixel-api-client": + version: 0.0.0-use.local + resolution: "@statsify/hypixel-api-client@workspace:packages/hypixel-api-client" + dependencies: + "@statsify/util": "workspace:^" + axios: ^0.27.2 + languageName: unknown + linkType: soft + "@statsify/logger@workspace:^, @statsify/logger@workspace:packages/logger": version: 0.0.0-use.local resolution: "@statsify/logger@workspace:packages/logger" @@ -1766,6 +1775,7 @@ __metadata: resolution: "@statsify/schemas@workspace:packages/schemas" dependencies: "@nestjs/swagger": ^6.0.1 + "@statsify/hypixel-api-client": "workspace:^" "@statsify/logger": "workspace:^" "@statsify/math": "workspace:^" "@statsify/util": "workspace:^" From 6ad7b36e464eefa4fb2902dccc70e8fb0f3f39d1 Mon Sep 17 00:00:00 2001 From: jacobk999 Date: Fri, 30 Dec 2022 09:27:14 -0500 Subject: [PATCH 4/5] update to node 18 --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 37e391feb..95c758cad 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.17.0 +v18.12.1 \ No newline at end of file From 11d44c75a2d2b91cf64ed9239c56ce3ce6a5f535 Mon Sep 17 00:00:00 2001 From: jacobk999 Date: Fri, 30 Dec 2022 15:48:53 -0500 Subject: [PATCH 5/5] move away from axios and rename some interfaces --- packages/hypixel-api-client/package.json | 3 +- packages/hypixel-api-client/src/index.ts | 205 +++++++++++------- .../src/types/base-hypixel-response.d.ts | 4 +- .../hypixel-api-client/src/types/helpers.d.ts | 4 +- .../src/types/player-stats.d.ts | 10 +- .../hypixel-api-client/src/types/player.d.ts | 124 ++++++----- .../hypixel-api-client/src/types/ranks.d.ts | 4 +- .../src/types/stats/pit-stats.d.ts | 70 +++--- yarn.lock | 1 - 9 files changed, 239 insertions(+), 186 deletions(-) diff --git a/packages/hypixel-api-client/package.json b/packages/hypixel-api-client/package.json index 725fd6044..88fdc0861 100644 --- a/packages/hypixel-api-client/package.json +++ b/packages/hypixel-api-client/package.json @@ -9,7 +9,6 @@ "lint": "TIMING=1 eslint './{src,tests}/**/*.{ts,tsx,js,jsx}' --fix" }, "dependencies": { - "@statsify/util": "workspace:^", - "axios": "^0.27.2" + "@statsify/util": "workspace:^" } } diff --git a/packages/hypixel-api-client/src/index.ts b/packages/hypixel-api-client/src/index.ts index bc42cb847..137975508 100644 --- a/packages/hypixel-api-client/src/index.ts +++ b/packages/hypixel-api-client/src/index.ts @@ -6,42 +6,100 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -import Axios, { AxiosError, AxiosInstance } from "axios"; import { HypixelPlayerResponse } from "./types"; import { setTimeout } from "node:timers/promises"; -export class HypixelKeyRejectedError extends Error { +export class HypixelAPIError extends Error { + public static BadRequest = new HypixelAPIError("Bad Request"); + public static InvalidAPIKey = new HypixelAPIError("Invalid API Key"); + public static NotFound = new HypixelAPIError("Not Found"); + public static InvalidData = new HypixelAPIError("Invalid Data"); + public static RatelimitExceeded = new HypixelAPIError("Ratelimit Exceeded"); + public static InternalServerError = new HypixelAPIError("Internal Server Error"); + public static DataUnavailable = new HypixelAPIError("Data Unavailable"); + public static UnknownError = new HypixelAPIError("Unknown Error"); + public static RequestTimeout = new HypixelAPIError("Request Timeout"); + public constructor(message: string) { super(message); - this.name = "EHYAPIKEY"; + this.name = HypixelAPIError.name; } -} -export class HypixelAPIError extends Error { - public constructor(message: string) { - super(message); - this.name = "EHYAPI"; + public static fromCode(code: number) { + switch (code) { + case 400: { + return HypixelAPIError.BadRequest; + } + case 403: { + return HypixelAPIError.InvalidAPIKey; + } + case 404: { + return HypixelAPIError.NotFound; + } + case 422: { + return HypixelAPIError.InvalidData; + } + case 429: { + return HypixelAPIError.RatelimitExceeded; + } + case 500: { + return HypixelAPIError.InternalServerError; + } + case 503: { + return HypixelAPIError.DataUnavailable; + } + default: { + return HypixelAPIError.UnknownError; + } + } } } -export type HypixelAPIConfig = { +export interface HypixelAPIConfig { key: string; autoSleep: boolean; -}; + timeout?: number; +} + +/** + * ID - Guild ID + * Player - Player UUID + * Name - Guild name + */ +export type GuildQuery = { id: string } | { player: string } | { name: string }; + +/** + * UUID - Auction UUID + * Player - Player UUID + * Profile - Profile UUID + */ +export type SkyblockAuctionQuery = + | { uuid: string } + | { player: string } + | { profile: string }; + +export type Resource = + | "games" + | "achievements" + | "challenges" + | "quests" + | "guilds/achievements" + | "vanity/pets" + | "vanity/companions" + | "skyblock/collections" + | "skyblock/skills" + | "skyblock/items" + | "skyblock/election" + | "skyblock/bingo"; export class HypixelAPI { public limit: number; public remaining: number; + public retryAfter?: number; - private axios: AxiosInstance; - private config: HypixelAPIConfig; - - public constructor(config: HypixelAPIConfig) { - this.axios = Axios.create({ - baseURL: "https://api.hypixel.net/", - headers: { "API-KEY": config.key }, - }); - this.config = config; + public constructor(private config: HypixelAPIConfig) { + this.limit = 120; + this.remaining = this.limit; } public player(uuid: string): Promise { @@ -60,7 +118,7 @@ export class HypixelAPI { return this.get("status", { uuid }); } - public guild(params: { id?: string; player?: string; name?: string }) { + public guild(params: GuildQuery) { return this.get("guild", params); } @@ -68,7 +126,7 @@ export class HypixelAPI { return this.get("boosters"); } - public counts() { + public gamecounts() { return this.get("counts"); } @@ -76,7 +134,7 @@ export class HypixelAPI { return this.get("leaderboards"); } - public punishmentstats() { + public watchdog() { return this.get("punishmentstats"); } @@ -84,7 +142,7 @@ export class HypixelAPI { return this.get("skyblock/news"); } - public skyblockAuction(params: { uuid?: string; player?: string; profile?: string }) { + public skyblockAuction(params: SkyblockAuctionQuery) { return this.get("skyblock/auction", params); } @@ -116,68 +174,65 @@ export class HypixelAPI { return this.get("skyblock/firesales"); } - public async getResource( - resource: - | "games" - | "achievements" - | "challenges" - | "quests" - | "guilds/achievements" - | "vanity/pets" - | "vanity/companions" - | "skyblock/collections" - | "skyblock/skills" - | "skyblock/items" - | "skyblock/election" - | "skyblock/bingo" - ) { - const response = await Axios.get(resource, { - baseURL: "https://api.hypixel.net/resources/", - }); - return response.data; + public async resource(resource: Resource) { + return this.get(`resources/${resource}`); } + /** + * + * @param endpoint The endpoint to fetch from https://api.hypixel.net/ + * @param params The query parameters to send + * @returns The API response + * @throws HypixelAPIError + */ private async get( endpoint: string, - params?: Record + params: Record = {} ): Promise { + const controller = new AbortController(); + + const url = new URL( + `https://api.hypixel.net${endpoint}?${new URLSearchParams(params)}` + ); + try { - const response = await this.axios.get(endpoint, { params }); + if (this.config.timeout) { + setTimeout(this.config.timeout, controller.abort.bind(controller)); + } + + const response = await fetch(url, { + headers: { "API-KEY": this.config.key }, + method: "GET", + signal: controller.signal, + }); + + const headers = response.headers; + const currentLimit = headers.get("rateLimit-limit"); + const currentRemaining = headers.get("rateLimit-remaining"); + const currentRetryAfter = headers.get("retry-after"); + + this.limit = currentLimit ? +currentLimit : this.limit; + this.remaining = currentRemaining ? +currentRemaining : this.remaining - 1; - this.limit = Number(response.headers["rateLimit-limit"]); - this.remaining = Number(response.headers["rateLimit-remaining"]); + if (currentRetryAfter) this.retryAfter = +currentRetryAfter * 1000; + if (!response.ok) throw HypixelAPIError.fromCode(response.status); - return response.data; + this.retryAfter = undefined; + + const data = await response.json(); + return data; } catch (error: any) { - switch (error.code) { - case 429: { - if (this.config.autoSleep) { - await setTimeout( - Number((error as AxiosError)?.response?.headers?.["retry-after"] ?? 60) * - 1000 - ); - return await this.get(endpoint, params); - } else { - throw error; - } - } - - case 403: { - throw new HypixelKeyRejectedError( - `Hypixel API key "${this.config.key}" was rejected!` - ); - } - - case 500: { - throw new HypixelAPIError( - "The Hypixel API has encountered an error with our request!" - ); - } - - default: { - throw error; - } + if (error === HypixelAPIError.RatelimitExceeded && this.config.autoSleep) { + const sleep = this.retryAfter ?? 60_000; + await setTimeout(sleep); + return this.get(endpoint, params); } + + this.retryAfter = undefined; + + if (error.name === "AbortError") throw HypixelAPIError.RequestTimeout; + + throw error; } } } diff --git a/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts b/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts index 10aa145ea..d375f7e45 100644 --- a/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts +++ b/packages/hypixel-api-client/src/types/base-hypixel-response.d.ts @@ -6,6 +6,6 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -export declare class BaseHypixelResponse { - public success: boolean; +export interface BaseHypixelResponse { + success: boolean; } diff --git a/packages/hypixel-api-client/src/types/helpers.d.ts b/packages/hypixel-api-client/src/types/helpers.d.ts index ec22e3e45..2871f0a88 100644 --- a/packages/hypixel-api-client/src/types/helpers.d.ts +++ b/packages/hypixel-api-client/src/types/helpers.d.ts @@ -26,13 +26,13 @@ export type IntRange = Exclude< Enumerate >; -interface BasicStats { +export interface BasicStats { [key: string]: any; coins?: number; lastTourneyAd?: number; } -interface NBTData { +export interface NBTData { type: number; data: ArrayBuffer; } diff --git a/packages/hypixel-api-client/src/types/player-stats.d.ts b/packages/hypixel-api-client/src/types/player-stats.d.ts index 279d4aa92..8258ecb52 100644 --- a/packages/hypixel-api-client/src/types/player-stats.d.ts +++ b/packages/hypixel-api-client/src/types/player-stats.d.ts @@ -7,12 +7,10 @@ */ import type { APIData, BasicStats } from "./helpers"; +import type { HypixelGameMode } from "./games"; import type { HypixelPitStats } from "./stats"; -interface IHypixelStats { - [key: HypixelGameMode]: BasicStats; +export type HypixelPlayerStats = { + [key: HypixelGameMode]: BasicStats | APIData; Pit: HypixelPitStats; -} - -export type HypixelPlayerStats = Record & - IHypixelStats; +}; diff --git a/packages/hypixel-api-client/src/types/player.d.ts b/packages/hypixel-api-client/src/types/player.d.ts index b7dea15ae..2323997f4 100644 --- a/packages/hypixel-api-client/src/types/player.d.ts +++ b/packages/hypixel-api-client/src/types/player.d.ts @@ -8,108 +8,114 @@ import { BaseHypixelResponse } from "./base-hypixel-response"; import { HypixelAchievementMode, HypixelGameMode, HypixelLobby } from "./games"; -import { HypixelNormalRanks } from "./ranks"; +import { HypixelNormalRank } from "./ranks"; import { HypixelPlayerStats } from "./player-stats"; export type ChallengesTime = `day_${string}` | "all__time"; export type AchievementName = `${HypixelAchievementMode}_${string}`; -export declare class HypixelPlayerChallenges { +export interface PeriodicChallenges { [key: `${Uppercase}_${string}`]: number; } -export declare class HypixelPlayerQuest { - public completions?: { time: number }[]; - public active?: { +export type Challenges = { + [key: ChallengesTime]: PeriodicChallenges; + all_time?: PeriodicChallenges; +}; + +export interface Quest { + completions?: { time: number }[]; + active?: { started?: number; objectives?: { [key: string]: number }; }; } -export declare class HypixelPlayer_Settings { - public fishCollectorShowCaught?: boolean; +export interface PlayerSettings { + fishCollectorShowCaught?: boolean; } -export declare class HypixelPlayerSeasonal { +export interface SeasonalStats { [key: "halloween" | "summer"]: { "2022"?: { levelling?: { experience: number } } }; - public silver: number; + silver: number; } -export type HypixelPlayerAchievementRewardsNew = { +export type AchievementRewardsNew = { [key: `for_points_${number}00`]: number; }; -export declare class HypixelPlayer { +export interface SocialMedia { + links: { + DISCORD?: string; + HYPIXEL?: string; + INSTAGRAM?: string; + MIXER?: string; + TWITCH?: string; + TWITTER?: string; + YOUTUBE?: string; + }; +} + +export type ParkourCompletions = { + [key: HypixelLobby]: { timeStart?: number; timeTook?: number }[]; +}; + +export interface HypixelPlayer { [key: string]: any; /** * The mongo ID of the player in hypixel */ - public _id?: string; + _id?: string; - public _settings?: HypixelPlayer_Settings; + _settings?: PlayerSettings; /** * The players UUID */ - public uuid: string; + uuid: string; /** * The timestamp of the players first login to hypixel */ - public firstLogin?: number; + firstLogin?: number; /** * The name of the player all lowercase */ - public playername?: Lowercase; + playername?: Lowercase; /** * The name of the player */ - public displayname: PName; - - public achievementsOneTime?: AchievementName[]; - public achievementRewardsNew?: HypixelPlayerAchievementRewardsNew; - public networkExp?: number; - public karma?: number; - public stats?: HypixelPlayerStats; - public socialMedia?: { - links: { - DISCORD?: string; - HYPIXEL?: string; - INSTAGRAM?: string; - MIXER?: string; - TWITCH?: string; - TWITTER?: string; - YOUTUBE?: string; - }; - }; - public achievements?: Record; - public newPackageRank?: HypixelNormalRanks; - public totalRewards?: number; - public totalDailyRewards?: number; - public rewardStreak?: number; - public rewardScore?: number; - public rewardHighScore?: number; - public achievementPoints?: number; - public battlePassGlowStatus?: boolean; - public firstLogin?: number; - public seasonal?: HypixelPlayerSeasonal; - public challenges?: { - [key: ChallengesTime]: HypixelPlayerChallenges; - all_time?: HypixelPlayerChallenges; - }; - public quests?: Record; - public parkourCheckpointBests?: { [key: HypixelLobby]: number[] }; - public parkourCompletions?: { - [key: HypixelLobby]: { timeStart?: number; timeTook?: number }[]; - }; - public rankPlusColor?: string; - public monthlyPackageRank?: "NONE" | "SUPERSTAR"; - public monthlyRankColor?: "GOLD" | "AQUA"; + displayname: PName; + + achievementsOneTime?: AchievementName[]; + achievementRewardsNew?: AchievementRewardsNew; + networkExp?: number; + karma?: number; + stats?: HypixelPlayerStats; + socialMedia?: SocialMedia; + achievements?: Record; + newPackageRank?: HypixelNormalRank; + totalRewards?: number; + totalDailyRewards?: number; + rewardStreak?: number; + rewardScore?: number; + rewardHighScore?: number; + achievementPoints?: number; + battlePassGlowStatus?: boolean; + firstLogin?: number; + seasonal?: SeasonalStats; + challenges?: Challenges; + quests?: Record; + parkourCheckpointBests?: { [key: HypixelLobby]: number[] }; + parkourCompletions?: ParkourCompletions; + rankPlusColor?: string; + monthlyPackageRank?: "NONE" | "SUPERSTAR"; + monthlyRankColor?: "GOLD" | "AQUA"; } -export declare class HypixelPlayerResponse extends BaseHypixelResponse { - public player: HypixelPlayer; +export interface HypixelPlayerResponse extends BaseHypixelResponse { + player: HypixelPlayer; } diff --git a/packages/hypixel-api-client/src/types/ranks.d.ts b/packages/hypixel-api-client/src/types/ranks.d.ts index f6ff51e39..8e431ed39 100644 --- a/packages/hypixel-api-client/src/types/ranks.d.ts +++ b/packages/hypixel-api-client/src/types/ranks.d.ts @@ -6,7 +6,7 @@ * https://github.com/Statsify/statsify/blob/main/LICENSE */ -export enum HypixelNormalRanks { +export enum HypixelNormalRank { "NONE", "NORMAL", "VIP", @@ -22,4 +22,4 @@ export enum HypixelSpecialRanks { "OWNER", } -export type HypixelRanks = HypixelNormalRanks | HypixelSpecialRanks; +export type HypixelRanks = HypixelNormalRank | HypixelSpecialRanks; diff --git a/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts b/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts index 4c9c505c7..897af1cb0 100644 --- a/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts +++ b/packages/hypixel-api-client/src/types/stats/pit-stats.d.ts @@ -8,12 +8,12 @@ import { BasicStats, IntRange, NBTData } from "../helpers"; -export enum HypixelPitGenesisFactions { +export enum PitGenesisFactions { angel = "angel", demon = "demon", } -export interface HypixelPitContract { +export interface PitContract { /** * either EASY or HARD, representing a Novice or Big Time contract respectively. */ @@ -52,7 +52,7 @@ export interface HypixelPitContract { key: string; } -export interface HypixelPitBounty { +export interface PitBounty { /** * The gold amount of the bounty bump */ @@ -69,7 +69,7 @@ export interface HypixelPitBounty { timestamp: number; } -interface HypixelPitShopsThrottle { +interface PitShopsThrottle { [key: `${"buyer_" | ""}${"Hay" | "Bread" | "Fish"}`]: { /** * The latest date the player sold items to that NPC. @@ -83,7 +83,7 @@ interface HypixelPitShopsThrottle { }; } -export interface HypixelPitStatsPTL { +export interface PitStatsPTL { assists: number; cash_earned: number; damage_dealt: number; @@ -179,7 +179,7 @@ export interface HypixelPitStatsPTL { gold_from_selling_fish: number; } -export interface HypixelPitOutgoingOffer { +export interface PitOutgoingOffer { /** * Unix timestamp of when the command was sent. */ @@ -216,32 +216,32 @@ export interface HypixelPitOutgoingOffer { target: string; } -export interface HypixelPitKingsQuest { +export interface PitKingsQuest { kills: number; renown: number; last_completed: number; last_accepted: number; } -export interface HypixelPitUnlocks { +export interface PitUnlocks { tier: number; acquireDate: number; key: string; } -export interface HypixelPitPrestiges { +export interface PitPrestiges { index: IntRange<1, 50>; xp_on_prestige: number; timestamp: number; } -export interface HypixelPitRenownUnlocks { +export interface PitRenownUnlocks { tier: number; acquireDate: number; key: string; } -export enum HypixelPitChatOptions { +export enum PitChatOptions { "kill_feed", "prestige_announcements", "minor_events", @@ -251,7 +251,7 @@ export enum HypixelPitChatOptions { "misc", } -export type IHypixelPitProfile = { +export interface PitProfile { // // All index types are here for use with iteration, // these are also all added as records to the actual type @@ -262,7 +262,7 @@ export type IHypixelPitProfile = { * Each unlock contains a "tier" (set to 0 if the upgrade has no tier), Unix timestamp, and a key. * The player's first prestige is stored as unlocks, not unlocks_0. */ - [unlocksIndex: `unlocks${"" | `_${number}`}`]: HypixelPitUnlocks; + [unlocksIndex: `unlocks${"" | `_${number}`}`]: PitUnlocks; /** * The player's selected perks. @@ -277,7 +277,7 @@ export type IHypixelPitProfile = { /** * The player's /pitchat settings. */ - [chatOption: `chat_option_${keyof typeof HypixelPitChatOptions}`]: boolean; + [chatOption: `chat_option_${keyof typeof PitChatOptions}`]: boolean; /** * Unix timestamps of when the player last claimed various faction items and perks. @@ -285,13 +285,13 @@ export type IHypixelPitProfile = { [ genesisClaims: `genesis_weekly_perks_${ | `perma_${"xp" | "gold"}` - | `claim_item_${HypixelPitGenesisFactions}`}` + | `claim_item_${PitGenesisFactions}`}` ]: number; /** * The number of times the player has claimed the Tier VII reward of the respective faction. */ - [genesisPerma: `genesis_perma_${HypixelPitGenesisFactions}`]: number; + [genesisPerma: `genesis_perma_${PitGenesisFactions}`]: number; /** * The player's selected killstreaks. @@ -306,7 +306,7 @@ export type IHypixelPitProfile = { /** * The current outgoing offers the player has,created with /offer. The objects, each corresponding to one use of the /offer command, contain several keys. */ - outgoing_offers: HypixelPitOutgoingOffer[]; + outgoing_offers: PitOutgoingOffer[]; /** * The Unix timestamp of the player's most recent save of their API stats. Updates to the current @@ -318,7 +318,7 @@ export type IHypixelPitProfile = { /** * Stats for the most recent King's Quest the player started. */ - king_quest: HypixelPitKingsQuest; + king_quest: PitKingsQuest; /** * Unix timestamp of when the player last received participation XP. @@ -364,7 +364,7 @@ export type IHypixelPitProfile = { /** * The player's currently in-progress contract. */ - contract: HypixelPitContract; + contract: PitContract; /** * Unix timestamp of the player's last completed contract. @@ -382,7 +382,7 @@ export type IHypixelPitProfile = { /** * The player's most recently-chosen faction on the Genesis map. */ - genesis_allegiance: Uppercase; + genesis_allegiance: Uppercase; /** * The player's inventory contents. Stored as a byte array. @@ -418,7 +418,7 @@ export type IHypixelPitProfile = { /** * Array of prestiges. */ - prestiges: HypixelPitPrestiges[]; + prestiges: PitPrestiges[]; /** * Byte array of the player's Spire stash inventory, containing the player's items that will be given @@ -442,7 +442,7 @@ export type IHypixelPitProfile = { /** * Contains several objects, each corresponding to a renown unlock. */ - renown_unlocks: HypixelPitRenownUnlocks[]; + renown_unlocks: PitRenownUnlocks[]; /** * Unix timestamp of the last time the player disconnected while in combat. @@ -479,12 +479,12 @@ export type IHypixelPitProfile = { number ]; - ended_contracts: HypixelPitContract[]; + ended_contracts: PitContract[]; /** * List of bounty bumps */ - bounties: HypixelPitBounty[]; + bounties: PitBounty[]; /** * Whether the player chooses to receive Night Quests. @@ -511,7 +511,7 @@ export type IHypixelPitProfile = { */ disable_spawn_items: boolean; - shops_throttle: HypixelPitShopsThrottle; + shops_throttle: PitShopsThrottle; /** * Array of items that the player has Autobuy enabled on. @@ -522,9 +522,7 @@ export type IHypixelPitProfile = { * List of the three contracts the player can select. * Returns null if the player has no contracts to select */ - contract_choices: - | [HypixelPitContract?, HypixelPitContract?, HypixelPitContract?] - | null; + contract_choices: [PitContract?, PitContract?, PitContract?] | null; /** * The player has in their Mystic Well. @@ -629,20 +627,20 @@ export type IHypixelPitProfile = { * Used by admins to test the contracts feature. */ contract_offers: any; -}; +} -export type HypixelPitProfile = IHypixelPitProfile & - Record<`unlocks${"" | `_${IntRange<1, 51>}`}`, HypixelPitUnlocks> & +export type HypixelPitProfile = PitProfile & + Record<`unlocks${"" | `_${IntRange<1, 51>}`}`, PitUnlocks> & Record<`selected_perk_${IntRange<0, 4>}`, string> & Record<`cash_during_prestige_${IntRange<0, 50>}`, number> & - Record<`chat_option_${keyof typeof HypixelPitChatOptions}`, boolean> & + Record<`chat_option_${keyof typeof PitChatOptions}`, boolean> & Record< `genesis_weekly_perks_${ | `perma_${"xp" | "gold"}` - | `claim_item_${keyof typeof HypixelPitGenesisFactions}`}`, + | `claim_item_${keyof typeof PitGenesisFactions}`}`, number > & - Record<`genesis_perma_${keyof typeof HypixelPitGenesisFactions}`, number> & + Record<`genesis_perma_${keyof typeof PitGenesisFactions}`, number> & Record<`selected_killstreak_${IntRange<1, 5>}`, string> & Record<`${"gold" | "xp"}_stack_streak_${IntRange<0, 51>}`, number> & Record<`selected_killstreak_${IntRange<1, 5>}`, string>; @@ -651,8 +649,6 @@ export interface HypixelPitStats extends BasicStats { packages?: ["supporter"]; restored_inv_backup_1?: number; stats_move_1: number; - pit_stats_ptl?: HypixelPitStatsPTL & unknown; + pit_stats_ptl?: PitStatsPTL & unknown; profile?: HypixelPitProfile; } - -(({} as HypixelPitProfile).selected_perk_1); diff --git a/yarn.lock b/yarn.lock index a2220963b..caac98d79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1736,7 +1736,6 @@ __metadata: resolution: "@statsify/hypixel-api-client@workspace:packages/hypixel-api-client" dependencies: "@statsify/util": "workspace:^" - axios: ^0.27.2 languageName: unknown linkType: soft