aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-04-09 17:22:00 -0500
committermat <github@matdoes.dev>2022-04-09 17:22:00 -0500
commit751b207c86c1e9bea14d48c0855fce5b62ddaba3 (patch)
tree1a4ee78abff537f1af7a5a0418aee2726f7ff211
parent0fe3c70af87813b73f2b263fe3314e69d57b4dbd (diff)
downloadskyblock-api-751b207c86c1e9bea14d48c0855fce5b62ddaba3.tar.gz
skyblock-api-751b207c86c1e9bea14d48c0855fce5b62ddaba3.tar.bz2
skyblock-api-751b207c86c1e9bea14d48c0855fce5b62ddaba3.zip
Add farming contest leaderboards
-rw-r--r--src/cleaners/skyblock/farmingContents.ts11
-rw-r--r--src/cleaners/skyblock/member.ts3
-rw-r--r--src/cleaners/skyblock/slayers.ts2
-rw-r--r--src/cleaners/skyblock/stats.ts10
-rw-r--r--src/constants.ts14
-rw-r--r--src/database.ts67
6 files changed, 96 insertions, 11 deletions
diff --git a/src/cleaners/skyblock/farmingContents.ts b/src/cleaners/skyblock/farmingContents.ts
index 218837d..75427ef 100644
--- a/src/cleaners/skyblock/farmingContents.ts
+++ b/src/cleaners/skyblock/farmingContents.ts
@@ -1,4 +1,5 @@
import typedHypixelApi from 'typed-hypixel-api'
+import { addCrops } from '../../constants.js'
import { cleanItemId } from './itemId.js'
export interface PlayerFarmingContestStats {
@@ -24,31 +25,37 @@ export interface FarmingContests {
list: PlayerFarmingContestStats[]
}
-export function cleanFarmingContests(data: typedHypixelApi.SkyBlockProfileMember): FarmingContests {
+export async function cleanFarmingContests(data: typedHypixelApi.SkyBlockProfileMember): Promise<FarmingContests> {
if (!data.jacob2) return {
talkedToJacob: false,
list: []
}
+ let cropNames: Set<string> = new Set()
+
const contestsByDate: Record<string, PlayerFarmingContestStats['crops']> = {}
for (const [contestName, contestData] of Object.entries(data.jacob2?.contests ?? {})) {
const [year, monthDay, item] = contestName.split(':')
const [month, day] = monthDay.split('_')
const contestByDateKey = `${year}:${month}:${day}`
+ const cropId = cleanItemId(item)
const cropData: PlayerFarmingContestStats['crops'][number] = {
- item: cleanItemId(item),
+ item: cropId,
amount: contestData.collected,
// the api returns the position 0-indexed, so we add 1
position: contestData.claimed_position !== undefined ? contestData.claimed_position + 1 : null,
claimed: contestData.claimed_rewards ?? null,
participants: contestData.claimed_participants ?? null
}
+ cropNames.add(cropId)
if (!(contestByDateKey in contestsByDate))
contestsByDate[contestByDateKey] = [cropData]
else
contestsByDate[contestByDateKey].push(cropData)
}
+ await addCrops(Array.from(cropNames))
+
const contestsByDateEntries = Object.entries(contestsByDate)
// this is to sort by newest first
contestsByDateEntries.reverse()
diff --git a/src/cleaners/skyblock/member.ts b/src/cleaners/skyblock/member.ts
index 6642976..57462ed 100644
--- a/src/cleaners/skyblock/member.ts
+++ b/src/cleaners/skyblock/member.ts
@@ -79,6 +79,7 @@ export async function cleanSkyBlockProfileMemberResponse(member: typedHypixelApi
const petsPromise = cleanPets(member)
const harpPromise = cleanHarp(member)
const inventoriesPromise = inventoriesIncluded ? cleanInventories(member) : Promise.resolve(undefined)
+ const farmingContestsPromise = cleanFarmingContests(member)
return {
uuid: member.uuid,
@@ -106,7 +107,7 @@ export async function cleanSkyBlockProfileMemberResponse(member: typedHypixelApi
pets: await petsPromise,
harp: await harpPromise,
coopInvitation: await coopInvitationPromise,
- farmingContests: cleanFarmingContests(member),
+ farmingContests: await farmingContestsPromise,
left: (player.profiles?.find(profile => profile.uuid === profileId) === undefined) ?? false
}
diff --git a/src/cleaners/skyblock/slayers.ts b/src/cleaners/skyblock/slayers.ts
index b5dda0b..6516bbf 100644
--- a/src/cleaners/skyblock/slayers.ts
+++ b/src/cleaners/skyblock/slayers.ts
@@ -66,7 +66,7 @@ export function cleanSlayers(data: typedHypixelApi.SkyBlockProfileMember): Slaye
for (const slayerDataKey in slayerDataRaw) {
// if a key starts with boss_kills_tier_ (boss_kills_tier_1), get the last number
if (slayerDataKey.startsWith('boss_kills_tier_')) {
- const slayerTierRaw = parseInt(slayerDataKey.substr('boss_kills_tier_'.length))
+ const slayerTierRaw = parseInt(slayerDataKey.slice('boss_kills_tier_'.length))
const slayerTierKills = slayerDataRaw[slayerDataKey] ?? 0
// add 1 since hypixel is using 0 indexed tiers
const slayerTier = slayerTierRaw + 1
diff --git a/src/cleaners/skyblock/stats.ts b/src/cleaners/skyblock/stats.ts
index 67099af..e5baa8f 100644
--- a/src/cleaners/skyblock/stats.ts
+++ b/src/cleaners/skyblock/stats.ts
@@ -9,6 +9,8 @@ const statCategories: { [key: string]: string[] | null } = { // sorted in order
'races': ['_best_time', '_best_time_2'],
'mythos': ['mythos_burrows_', 'mythos_kills'],
+ 'farming_contests': ['farming_contests_'],
+
'collection': ['collection_'],
'skills': ['skill_'],
'slayer': ['slayer_'],
@@ -37,16 +39,16 @@ export function categorizeStat(statNameRaw: string): StatCategory {
for (const categoryMatch of statCategoryMatchers) {
// ['deaths_']
let trailingEnd = categoryMatch[0] === '_'
- let trailingStart = categoryMatch.substr(-1) === '_'
+ let trailingStart = categoryMatch.slice(-1) === '_'
if (trailingStart && statNameRaw.startsWith(categoryMatch)) {
return {
category: statCategory,
- name: statNameRaw.substr(categoryMatch.length)
+ name: statNameRaw.slice(categoryMatch.length)
}
} else if (trailingEnd && statNameRaw.endsWith(categoryMatch)) {
return {
category: statCategory,
- name: statNameRaw.substr(0, statNameRaw.length - categoryMatch.length)
+ name: statNameRaw.slice(0, statNameRaw.length - categoryMatch.length)
}
} else if (statNameRaw == categoryMatch) {
// if it matches exactly, we don't know the name. will be defaulted to category later on
@@ -83,7 +85,7 @@ export function getStatUnit(name: string): string | null {
for (const [unitName, statMatchers] of Object.entries(statUnits)) {
for (const statMatch of statMatchers) {
let trailingEnd = statMatch[0] === '_'
- let trailingStart = statMatch.substr(-1) === '_'
+ let trailingStart = statMatch.slice(-1) === '_'
if (
(trailingStart && name.startsWith(statMatch))
|| (trailingEnd && name.endsWith(statMatch))
diff --git a/src/constants.ts b/src/constants.ts
index 1371250..14254ed 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -120,6 +120,9 @@ async function editFile(file: GithubFile, message: string, newContent: string):
}
)
const data = await r.json() as any
+ if (!data.content?.path)
+ // failed to set the data, probably ratelimited or something
+ return
fileCache.set(file.path, {
path: data.content.path,
content: newContent,
@@ -254,6 +257,17 @@ export async function addHarpSongs(addingSongs: string[]): Promise<void> {
}
+/** Fetch all the known crops (used in farming contests) as an array of strings */
+export async function fetchCrops(): Promise<string[]> {
+ return await constants.fetchJSONConstant('crops.json')
+}
+
+/** Add crop names (used in farming contests) to skyblock-constants. This has caching so it's fine to call many times */
+export async function addCrops(addingCrops: string[]): Promise<void> {
+ await constants.addJSONConstants('crops.json', addingCrops, 'crop')
+}
+
+
interface constantValues {
max_minions?: number
max_fairy_souls?: number
diff --git a/src/database.ts b/src/database.ts
index a95878f..fa4cbd2 100644
--- a/src/database.ts
+++ b/src/database.ts
@@ -184,6 +184,47 @@ function getMemberHarpAttributes(member: CleanMember): StringNumber {
return harpAttributes
}
+function getFarmingContestAttributes(member: CleanMember): StringNumber {
+ const farmingContestAttributes: StringNumber = {}
+
+ let participated = 0
+ let top1 = 0
+
+ let participatedRecord: StringNumber = {}
+ let top1Record: StringNumber = {}
+ let highestScoreRecord: StringNumber = {}
+
+ for (const contest of member.farmingContests.list) {
+ participated++
+ for (const cropContest of contest.crops) {
+ if (participatedRecord[cropContest.item] === undefined)
+ participatedRecord[cropContest.item] = 0
+ participatedRecord[cropContest.item]++
+
+ if (highestScoreRecord[cropContest.item] === undefined || highestScoreRecord[cropContest.item] < cropContest.amount)
+ highestScoreRecord[cropContest.item] = cropContest.amount
+
+ if (cropContest.position === 1) {
+ top1++
+ if (top1Record[cropContest.item] === undefined)
+ top1Record[cropContest.item] = 0
+ top1Record[cropContest.item]++
+ }
+ }
+ }
+ farmingContestAttributes['farming_contests_participated'] = participated
+ farmingContestAttributes['farming_contests_top_1'] = top1
+
+ for (const [cropName, value] of Object.entries(participatedRecord))
+ farmingContestAttributes[`farming_contests_participated_${cropName}`] = value
+ for (const [cropName, value] of Object.entries(top1Record))
+ farmingContestAttributes[`farming_contests_top_1_${cropName}`] = value
+ for (const [cropName, value] of Object.entries(highestScoreRecord))
+ farmingContestAttributes[`farming_contests_highest_score_${cropName}`] = value
+
+ return farmingContestAttributes
+}
+
function getMemberLeaderboardAttributes(member: CleanMember): StringNumber {
// if you want to add a new leaderboard for member attributes, add it here (and getAllLeaderboardAttributes)
const data: StringNumber = {
@@ -202,6 +243,9 @@ function getMemberLeaderboardAttributes(member: CleanMember): StringNumber {
// harp leaderboards
...getMemberHarpAttributes(member),
+ // farming contest leaderboards
+ ...getFarmingContestAttributes(member),
+
fairy_souls: member.fairySouls.total,
purse: member.purse,
visited_zones: member.zones.filter(z => z.visited).length,
@@ -270,7 +314,7 @@ export async function fetchSlayerLeaderboards(): Promise<string[]> {
return leaderboardNames
}
-export async function fetchHarpLeaderboards(): Promise<string[]> {
+async function fetchHarpLeaderboards(): Promise<string[]> {
const harpSongs = await constants.fetchHarpSongs()
const leaderboardNames: string[] = []
@@ -282,6 +326,20 @@ export async function fetchHarpLeaderboards(): Promise<string[]> {
return leaderboardNames
}
+async function fetchFarmingContestLeaderboards(): Promise<string[]> {
+ const leaderboardNames: string[] = []
+
+ leaderboardNames.push(`farming_contests_participated`)
+ leaderboardNames.push(`farming_contests_top_1`)
+ for (const crop of await constants.fetchCrops()) {
+ leaderboardNames.push(`farming_contests_participated_${crop}`)
+ leaderboardNames.push(`farming_contests_top_1_${crop}`)
+ leaderboardNames.push(`farming_contests_highest_score_${crop}`)
+ }
+
+ return leaderboardNames
+}
+
/** Fetch the names of all the leaderboards that rank members */
export async function fetchAllMemberLeaderboardAttributes(): Promise<string[]> {
return [
@@ -300,6 +358,9 @@ export async function fetchAllMemberLeaderboardAttributes(): Promise<string[]> {
// harp leaderboards
...await fetchHarpLeaderboards(),
+ // farming contest leaderboards
+ ...await fetchFarmingContestLeaderboards(),
+
'fairy_souls',
'first_join',
'last_save',
@@ -308,7 +369,7 @@ export async function fetchAllMemberLeaderboardAttributes(): Promise<string[]> {
'leaderboards_count',
'top_1_leaderboards_count',
'fastest_coop_join',
- 'slowest_coop_join'
+ 'slowest_coop_join',
]
}
@@ -322,7 +383,7 @@ async function fetchAllProfileLeaderboardAttributes(): Promise<string[]> {
function isLeaderboardReversed(name: string): boolean {
for (const leaderboardMatch of reversedLeaderboards) {
let trailingEnd = leaderboardMatch[0] === '_'
- let trailingStart = leaderboardMatch.substr(-1) === '_'
+ let trailingStart = leaderboardMatch.slice(-1) === '_'
if (
(trailingStart && name.startsWith(leaderboardMatch))
|| (trailingEnd && name.endsWith(leaderboardMatch))