diff options
| author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2024-05-02 16:01:39 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-02 16:01:39 +0200 |
| commit | 6c8fc0df08331da7e49796985a1df5f14e6d7ac3 (patch) | |
| tree | 3fb6f00ae187e3197d98de37d72168a860ee4d71 /src/main/java/at/hannibal2/skyhanni/data/bazaar | |
| parent | 4353efaa3d18a61f49f79273bea63303afcab7e1 (diff) | |
| download | skyhanni-6c8fc0df08331da7e49796985a1df5f14e6d7ac3.tar.gz skyhanni-6c8fc0df08331da7e49796985a1df5f14e6d7ac3.tar.bz2 skyhanni-6c8fc0df08331da7e49796985a1df5f14e6d7ac3.zip | |
Backend: Bazaar Fetcher (#1597)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Co-authored-by: Cal <cwolfson58@gmail.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/data/bazaar')
| -rw-r--r-- | src/main/java/at/hannibal2/skyhanni/data/bazaar/BazaarJson.kt | 36 | ||||
| -rw-r--r-- | src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt | 100 |
2 files changed, 136 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/bazaar/BazaarJson.kt b/src/main/java/at/hannibal2/skyhanni/data/bazaar/BazaarJson.kt new file mode 100644 index 000000000..350f33db2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/bazaar/BazaarJson.kt @@ -0,0 +1,36 @@ +package at.hannibal2.skyhanni.data.bazaar + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +class BazaarApiResponseJson( + @Expose val success: Boolean, + @Expose val cause: String, + @Expose val lastUpdated: Long, + @Expose val products: Map<String, BazaarProduct>, +) + +data class BazaarProduct( + @Expose @SerializedName("product_id") val productId: String, + @Expose @SerializedName("quick_status") val quickStatus: BazaarQuickStatus, + @Expose @SerializedName("sell_summary") val sellSummary: List<BazaarSummary>, + @Expose @SerializedName("buy_summary") val buySummary: List<BazaarSummary>, +) + +class BazaarQuickStatus( + @Expose val productId: String, + @Expose val sellPrice: Double, + @Expose val sellVolume: Long, + @Expose val sellMovingWeek: Long, + @Expose val sellOrders: Long, + @Expose val buyPrice: Double, + @Expose val buyVolume: Long, + @Expose val buyMovingWeek: Long, + @Expose val buyOrders: Long, +) + +data class BazaarSummary( + @Expose val amount: Long, + @Expose val pricePerUnit: Double, + @Expose val orders: Long, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt new file mode 100644 index 000000000..148fb633a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt @@ -0,0 +1,100 @@ +package at.hannibal2.skyhanni.data.bazaar + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigManager +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarData +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.fromJson +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +// https://api.hypixel.net/#tag/SkyBlock/paths/~1v2~1skyblock~1bazaar/get +object HypixelBazaarFetcher { + private const val URL = "https://api.hypixel.net/v2/skyblock/bazaar" + private const val HIDDEN_FAILED_ATTEMPTS = 3 + + var latestProductInformation = mapOf<NEUInternalName, BazaarData>() + private var nextFetchTime = SimpleTimeMark.farPast() + private var failedAttempts = 0 + private var nextFetchIsManual = false + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!canFetch()) return + SkyHanniMod.coroutineScope.launch { + fetchAndProcessBazaarData() + } + } + + private suspend fun fetchAndProcessBazaarData() { + nextFetchTime = SimpleTimeMark.now() + 2.minutes + val fetchType = if (nextFetchIsManual) "manual" else "automatic" + nextFetchIsManual = false + try { + val jsonResponse = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(URL) }.asJsonObject + val response = ConfigManager.gson.fromJson<BazaarApiResponseJson>(jsonResponse) + if (response.success) { + latestProductInformation = process(response.products) + failedAttempts = 0 + } else { + onError(fetchType, Exception("success=false, cause=${response.cause}")) + } + } catch (e: Exception) { + onError(fetchType, e) + } + } + + private fun process(products: Map<String, BazaarProduct>) = products.mapNotNull { (key, product) -> + val internalName = NEUItems.transHypixelNameToInternalName(key) + val sellOfferPrice = product.buySummary.minOfOrNull { it.pricePerUnit } ?: 0.0 + val insantBuyPrice = product.sellSummary.maxOfOrNull { it.pricePerUnit } ?: 0.0 + if (internalName.getItemStackOrNull() == null) { + // Items that exist in Hypixel's Bazaar API, but not in NEU repo (not visible in in the ingame bazaar). + // Should only include Enchants + if (LorenzUtils.debug) + println("Unknown bazaar product: $key/$internalName") + return@mapNotNull null + } + internalName to BazaarData(internalName.itemName, sellOfferPrice, insantBuyPrice, product) + }.toMap() + + private fun onError(fetchType: String, e: Exception) { + val userMessage = "Failed fetching bazaar price data from hypixel" + failedAttempts++ + if (failedAttempts <= HIDDEN_FAILED_ATTEMPTS) { + nextFetchTime = SimpleTimeMark.now() + 15.seconds + ChatUtils.debug("$userMessage. (errorMessage=${e.message}, failedAttepmts=$failedAttempts, $fetchType") + e.printStackTrace() + } else { + nextFetchTime = SimpleTimeMark.now() + 15.minutes + ErrorManager.logErrorWithData( + e, + userMessage, + "fetchType" to fetchType, + "failedAttepmts" to failedAttempts, + ) + } + } + + fun fetchNow() { + failedAttempts = 0 + nextFetchIsManual = true + nextFetchTime = SimpleTimeMark.now() + ChatUtils.chat("Manually updating the bazaar prices right now..") + } + + private fun canFetch() = LorenzUtils.onHypixel && nextFetchTime.isInPast() +} |
