aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt
diff options
context:
space:
mode:
authorhannibal2 <24389977+hannibal00212@users.noreply.github.com>2023-01-06 23:27:58 +0100
committerhannibal2 <24389977+hannibal00212@users.noreply.github.com>2023-01-06 23:27:58 +0100
commit1b066b9cc3f2267750719b5fa52b4173f9662c1c (patch)
treeb726d36421c732f277912b36f150b596a9b6c1f4 /src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt
parent640bc1dfb63b974712ff0c69bec3606378f69afa (diff)
downloadskyhanni-1b066b9cc3f2267750719b5fa52b4173f9662c1c.tar.gz
skyhanni-1b066b9cc3f2267750719b5fa52b4173f9662c1c.tar.bz2
skyhanni-1b066b9cc3f2267750719b5fa52b4173f9662c1c.zip
Reloading the profile data every 3 minutes.
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt b/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt
new file mode 100644
index 000000000..bea039212
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt
@@ -0,0 +1,146 @@
+package at.hannibal2.skyhanni.data
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.events.ProfileApiDataLoadedEvent
+import at.hannibal2.skyhanni.events.ProfileJoinEvent
+import at.hannibal2.skyhanni.utils.APIUtil
+import at.hannibal2.skyhanni.utils.LorenzUtils
+import at.hannibal2.skyhanni.utils.StringUtils.toDashlessUUID
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import net.minecraft.client.Minecraft
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+import java.io.File
+import java.util.*
+
+class ApiDataLoader {
+
+ private var currentProfileName = ""
+
+ private var nextApiCallTime = -1L
+ private var currentProfileId = ""
+
+ @SubscribeEvent
+ fun onTick(event: TickEvent.ClientTickEvent) {
+ val thePlayer = Minecraft.getMinecraft().thePlayer ?: return
+ thePlayer.worldObj ?: return
+
+ if (nextApiCallTime != -1L && System.currentTimeMillis() > nextApiCallTime) {
+ nextApiCallTime = System.currentTimeMillis() + 60_000 * 5
+ SkyHanniMod.coroutineScope.launch {
+ val apiKey = SkyHanniMod.feature.hidden.apiKey
+ val uuid = Minecraft.getMinecraft().thePlayer.uniqueID.toDashlessUUID()
+ loadProfileData(apiKey, uuid, currentProfileId)
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onStatusBar(event: LorenzChatEvent) {
+ val message = event.message
+ if (message.startsWith("§aYour new API key is §r§b")) {
+ SkyHanniMod.feature.hidden.apiKey = message.substring(26)
+ LorenzUtils.chat("§b[SkyHanni] A new API Key has been detected and installed")
+
+ if (currentProfileName != "") {
+ updateApiData()
+ }
+ }
+ }
+
+ @SubscribeEvent
+ fun onStatusBar(event: ProfileJoinEvent) {
+ currentProfileName = event.name
+ updateApiData()
+ }
+
+ private suspend fun tryUpdateProfileDataAndVerifyKey(apiKey: String): Boolean {
+ val uuid = Minecraft.getMinecraft().thePlayer.uniqueID.toDashlessUUID()
+ val url = "https://api.hypixel.net/player?key=$apiKey&uuid=$uuid"
+ val jsonObject = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }
+
+ if (jsonObject["success"]?.asBoolean == false) {
+ if (jsonObject["throttle"]?.asBoolean == true) return true // 429 Too Many Requests does not make an invalid key.
+ val cause = jsonObject["cause"].asString
+ if (cause == "Invalid API key") {
+ return false
+ } else {
+ throw RuntimeException("API error for url '$url': $cause")
+ }
+ }
+ val player = jsonObject["player"].asJsonObject
+ val stats = player["stats"].asJsonObject
+ val skyBlock = stats["SkyBlock"].asJsonObject
+ val profiles = skyBlock["profiles"].asJsonObject
+ for (entry in profiles.entrySet()) {
+ val asJsonObject = entry.value.asJsonObject
+ val name = asJsonObject["cute_name"].asString
+ if (currentProfileName == name.lowercase()) {
+ currentProfileId = asJsonObject["profile_id"].asString
+ loadProfileData(apiKey, uuid, currentProfileId)
+ }
+ }
+ return true
+ }
+
+ private fun updateApiData() {
+ nextApiCallTime = -1
+ SkyHanniMod.coroutineScope.launch {
+ val oldApiKey = SkyHanniMod.feature.hidden.apiKey
+ if (oldApiKey.isNotEmpty() && tryUpdateProfileDataAndVerifyKey(oldApiKey)) {
+ return@launch
+ }
+ findApiCandidatesFromOtherMods().forEach { (modName, newApiKey) ->
+ if (tryUpdateProfileDataAndVerifyKey(newApiKey)) {
+ SkyHanniMod.feature.hidden.apiKey = newApiKey
+ LorenzUtils.chat("§e[SkyHanni] Imported valid new API key from $modName.")
+ return@launch
+ } else {
+ LorenzUtils.error("§c[SkyHanni] Invalid API key from $modName")
+ }
+ }
+ LorenzUtils.error("§c[SkyHanni] SkyHanni has no API key set. Please run /api new")
+ }
+ }
+
+ private fun findApiCandidatesFromOtherMods(): Map<String, String> {
+ LorenzUtils.consoleLog("Trying to find the API Key from the config of other mods..")
+ val candidates = mutableMapOf<String, String>()
+ for (mod in OtherMod.values()) {
+ val modName = mod.modName
+ val file = File(mod.configPath)
+ if (file.exists()) {
+ val reader = APIUtil.readFile(file)
+ try {
+ val key = mod.readKey(reader).replace("\n", "").replace(" ", "")
+ UUID.fromString(key)
+ candidates[modName] = key
+ } catch (e: Throwable) {
+ LorenzUtils.consoleLog("- $modName: wrong config format! (" + e.message + ")")
+ continue
+ }
+ } else {
+ LorenzUtils.consoleLog("- $modName: no config found!")
+ }
+ }
+ return candidates
+ }
+
+ private suspend fun loadProfileData(apiKey: String, playerUuid: String, profileId: String) {
+ val url = "https://api.hypixel.net/skyblock/profile?key=$apiKey&profile=$profileId"
+
+ val jsonObject = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(url) }
+ val profile = jsonObject["profile"]?.asJsonObject ?: return
+ val members = profile["members"]?.asJsonObject ?: return
+ for (entry in members.entrySet()) {
+ if (entry.key == playerUuid) {
+ val profileData = entry.value.asJsonObject
+ ProfileApiDataLoadedEvent(profileData).postAndCatch()
+ nextApiCallTime = System.currentTimeMillis() + 60_000 * 3
+ }
+ }
+ }
+}