1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import typedHypixelApi from 'typed-hypixel-api'
const statCategories: { [key: string]: string[] | null } = { // sorted in order of importance
'deaths': ['deaths_', 'deaths'],
'kills': ['kills_', 'kills'],
'fishing': ['items_fished_', 'items_fished', 'shredder_'],
'auctions': ['auctions_'],
'races': ['_best_time', '_best_time_2'],
'mythos': ['mythos_burrows_', 'mythos_kills'],
'collection': ['collection_'],
'skills': ['skill_'],
'slayer': ['slayer_'],
'harp': ['harp_'],
'misc': null // everything else goes here
}
export interface StatCategory {
category: string | null
name: string | null
}
export function categorizeStat(statNameRaw: string): StatCategory {
// 'deaths_void'
for (const statCategory in statCategories) {
// 'deaths'
const statCategoryMatchers = statCategories[statCategory]
if (statCategoryMatchers == null) {
// If it's null, just go with this. Can only ever be 'misc'
return {
category: statCategory,
name: statNameRaw
}
}
for (const categoryMatch of statCategoryMatchers) {
// ['deaths_']
let trailingEnd = categoryMatch[0] === '_'
let trailingStart = categoryMatch.substr(-1) === '_'
if (trailingStart && statNameRaw.startsWith(categoryMatch)) {
return {
category: statCategory,
name: statNameRaw.substr(categoryMatch.length)
}
} else if (trailingEnd && statNameRaw.endsWith(categoryMatch)) {
return {
category: statCategory,
name: statNameRaw.substr(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
return {
category: statCategory,
name: null
}
}
}
}
// this should never happen, as it'll default to misc and return if nothing is found
return {
category: null,
name: statNameRaw
}
}
export const statUnits = {
time: ['_best_time', '_best_time_2'],
date: ['first_join', 'last_save'],
coins: ['purse'],
leaderboards: ['leaderboards_count', 'top_1_leaderboards_count']
}
export interface StatItem {
rawName: string
value: number
categorizedName: string
category: string | null
unit: string | null
}
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) === '_'
if (
(trailingStart && name.startsWith(statMatch))
|| (trailingEnd && name.endsWith(statMatch))
|| (name == statMatch)
)
return unitName
}
}
return null
}
export function cleanProfileStats(data: typedHypixelApi.SkyBlockProfileMember): StatItem[] {
// TODO: add type for statsRaw (probably in hypixelApi.ts since its coming from there)
const stats: StatItem[] = []
const rawStats = data?.stats ?? {}
for (const statNameRaw in rawStats) {
const statValue = rawStats[statNameRaw]
let { category: statCategory, name: statName } = categorizeStat(statNameRaw)
stats.push({
categorizedName: statName ?? 'total',
value: statValue,
rawName: statNameRaw,
category: statCategory,
unit: getStatUnit(statNameRaw) ?? null
})
}
return stats
}
|