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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
/*
* Copyright (C) 2023 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github.moulberry.notenoughupdates.util.hypixelapi
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import io.github.moulberry.notenoughupdates.NotEnoughUpdates
import java.math.BigInteger
import java.util.concurrent.CompletableFuture
import kotlin.collections.List
import kotlin.collections.Map
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.filter
import kotlin.collections.flatMap
import kotlin.collections.groupBy
import kotlin.collections.mapNotNull
import kotlin.collections.mapValues
import kotlin.collections.maxOf
import kotlin.collections.sumOf
import kotlin.collections.toList
import kotlin.collections.toMap
import kotlin.collections.toSet
data class ProfileCollectionInfo(
val collections: Map<String, CollectionInfo>,
val craftedGenerators: Map<String, Int>,
) {
data class CollectionInfo(
val collection: Collection,
val totalCollectionCount: BigInteger,
val personalCollectionCount: BigInteger,
val unlockedTiers: List<CollectionTier>,
)
class CollectionMetadata internal constructor() {
lateinit var collections: Map<String, CollectionCategory>
private set
val allCollections by lazy { collections.values.flatMap { it.items.toList() }.toMap() }
}
class CollectionCategory internal constructor() {
lateinit var items: Map<String, Collection>
private set
}
class Collection internal constructor() {
lateinit var name: String
private set
var maxTiers: Int = -1
private set
lateinit var tiers: List<CollectionTier>
private set
override fun toString(): String {
return "Collection(name=$name, maxTiers=$maxTiers, tiers=$tiers)"
}
}
class CollectionTier internal constructor() {
var tier: Int = -1
private set
var amountRequired: Int = -1
private set
lateinit var unlocks: List<String>
private set
override fun toString(): String {
return "CollectionTier(tier=$tier, amountRequired=$amountRequired, unlocks=$unlocks)"
}
}
companion object {
val generatorPattern = "^([^0-9]+)_([0-9]+)$".toRegex()
val hypixelCollectionInfo: CompletableFuture<CollectionMetadata> by lazy {
NotEnoughUpdates.INSTANCE.manager.apiUtils
.newAnonymousHypixelApiRequest("resources/skyblock/collections")
.requestJson()
.thenApply {
NotEnoughUpdates.INSTANCE.manager.gson.fromJson(it, CollectionMetadata::class.java)
}
}
fun getCollectionData(
profileData: JsonObject,
mainPlayer: String,
collectionData: CollectionMetadata
): ProfileCollectionInfo? {
val mainPlayerUUID = mainPlayer.replace("-", "")
val members = profileData["members"] as? JsonObject ?: return null
val mainPlayerData =
(members[mainPlayerUUID] as? JsonObject ?: return null)
val mainPlayerCollection = mainPlayerData["collection"] as? JsonObject ?: return null
val memberCollections = members.entrySet().mapNotNull { (uuid, data) ->
if (data !is JsonObject) return null
data["collection"] as? JsonObject
}
val generators = members.entrySet().mapNotNull { (uuid, data) ->
if (data !is JsonObject) return null
data.getAsJsonObject("player_data")?.get("crafted_generators") as? JsonArray
}.flatMap { it.toList() }
return ProfileCollectionInfo(
collectionData.allCollections.mapValues { (name, collection) ->
val totalCollection = memberCollections.sumOf { it[name]?.asBigInteger ?: BigInteger.ZERO }
val personalCollection = mainPlayerCollection[name]?.asBigInteger ?: BigInteger.ZERO
CollectionInfo(
collection,
totalCollection,
personalCollection,
collection.tiers.filter { BigInteger.valueOf(it.amountRequired.toLong()) <= totalCollection }
)
},
generators.toSet()
.mapNotNull {
val pattern = generatorPattern.matchEntire(it.asString) ?: return@mapNotNull null
pattern.groupValues[1] to pattern.groupValues[2].toInt()
}
.groupBy { it.first }
.mapValues {
it.value.maxOf { it.second }
}
.toMap()
)
}
/**
* This should be the json object returned by /skyblock/profiles at profiles.<somenumber>. (aka the root tag
* should contain profile_id, members, cute_name, etc.)
*/
@JvmStatic
fun getCollectionData(profileData: JsonObject, mainPlayer: String): CompletableFuture<ProfileCollectionInfo?> {
return hypixelCollectionInfo.thenApply {
getCollectionData(profileData, mainPlayer, it)
}
}
}
}
|