diff options
author | Linnea Gräf <nea@nea.moe> | 2024-11-17 17:29:15 +0100 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-11-17 17:29:15 +0100 |
commit | 970dfddaf9e80d6b206f411139227397f4d9e847 (patch) | |
tree | 999f15cf28127c2053058dd877f6354540c22553 /src | |
parent | 915ab96b2444fa2e93d99a9747861b619d77f8f8 (diff) | |
download | Firmament-970dfddaf9e80d6b206f411139227397f4d9e847.tar.gz Firmament-970dfddaf9e80d6b206f411139227397f4d9e847.tar.bz2 Firmament-970dfddaf9e80d6b206f411139227397f4d9e847.zip |
feat: Add bazaar/ah search hotkey
Diffstat (limited to 'src')
-rw-r--r-- | src/main/kotlin/Firmament.kt | 2 | ||||
-rw-r--r-- | src/main/kotlin/events/ClientInitEvent.kt | 5 | ||||
-rw-r--r-- | src/main/kotlin/features/FeatureManager.kt | 3 | ||||
-rw-r--r-- | src/main/kotlin/features/inventory/ItemHotkeys.kt | 39 | ||||
-rw-r--r-- | src/main/kotlin/features/mining/HotmPresets.kt | 3 | ||||
-rw-r--r-- | src/main/kotlin/repo/HypixelStaticData.kt | 152 | ||||
-rw-r--r-- | src/main/kotlin/repo/ItemCache.kt | 9 | ||||
-rw-r--r-- | src/main/kotlin/util/MC.kt | 1 | ||||
-rw-r--r-- | src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt | 36 | ||||
-rw-r--r-- | src/main/kotlin/util/skyblock/SBItemUtil.kt | 21 |
10 files changed, 193 insertions, 78 deletions
diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt index 9f15bff..2c2a6b7 100644 --- a/src/main/kotlin/Firmament.kt +++ b/src/main/kotlin/Firmament.kt @@ -35,6 +35,7 @@ import kotlin.coroutines.EmptyCoroutineContext import net.minecraft.command.CommandRegistryAccess import net.minecraft.util.Identifier import moe.nea.firmament.commands.registerFirmamentCommand +import moe.nea.firmament.events.ClientInitEvent import moe.nea.firmament.events.ClientStartedEvent import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.ItemTooltipEvent @@ -141,6 +142,7 @@ object Firmament { ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext)) }) }) + ClientInitEvent.publish(ClientInitEvent()) } diff --git a/src/main/kotlin/events/ClientInitEvent.kt b/src/main/kotlin/events/ClientInitEvent.kt new file mode 100644 index 0000000..7d13d65 --- /dev/null +++ b/src/main/kotlin/events/ClientInitEvent.kt @@ -0,0 +1,5 @@ +package moe.nea.firmament.events + +class ClientInitEvent : FirmamentEvent() { + companion object : FirmamentEventBus<ClientInitEvent>() +} diff --git a/src/main/kotlin/features/FeatureManager.kt b/src/main/kotlin/features/FeatureManager.kt index 55f6328..2110d09 100644 --- a/src/main/kotlin/features/FeatureManager.kt +++ b/src/main/kotlin/features/FeatureManager.kt @@ -90,6 +90,9 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature fun subscribeEvents() { SubscriptionList.allLists.forEach { it.provideSubscriptions { + it.owner.javaClass.classes.forEach { + runCatching { it.getDeclaredField("INSTANCE").get(null) } + } subscribeSingleEvent(it) } } diff --git a/src/main/kotlin/features/inventory/ItemHotkeys.kt b/src/main/kotlin/features/inventory/ItemHotkeys.kt new file mode 100644 index 0000000..4aa8202 --- /dev/null +++ b/src/main/kotlin/features/inventory/ItemHotkeys.kt @@ -0,0 +1,39 @@ +package moe.nea.firmament.features.inventory + +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.HandledScreenKeyPressedEvent +import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.repo.HypixelStaticData +import moe.nea.firmament.repo.ItemCache +import moe.nea.firmament.repo.ItemCache.asItemStack +import moe.nea.firmament.repo.ItemCache.isBroken +import moe.nea.firmament.repo.RepoManager +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.focusedItemStack +import moe.nea.firmament.util.skyBlockId +import moe.nea.firmament.util.skyblock.SBItemUtil.getSearchName + +object ItemHotkeys { + object TConfig : ManagedConfig("item-hotkeys", Category.INVENTORY) { + val openGlobalTradeInterface by keyBindingWithDefaultUnbound("global-trade-interface") + } + + @Subscribe + fun onHandledInventoryPress(event: HandledScreenKeyPressedEvent) { + if (!event.matches(TConfig.openGlobalTradeInterface)) { + return + } + var item = event.screen.focusedItemStack ?: return + val skyblockId = item.skyBlockId ?: return + item = RepoManager.getNEUItem(skyblockId)?.asItemStack()?.takeIf { !it.isBroken } ?: item + if (HypixelStaticData.hasBazaarStock(skyblockId)) { + MC.sendCommand("bz ${item.getSearchName()}") + } else if (HypixelStaticData.hasAuctionHouseOffers(skyblockId)) { + MC.sendCommand("ahs ${item.getSearchName()}") + } else { + return + } + event.cancel() + } + +} diff --git a/src/main/kotlin/features/mining/HotmPresets.kt b/src/main/kotlin/features/mining/HotmPresets.kt index 533aa1e..2241fee 100644 --- a/src/main/kotlin/features/mining/HotmPresets.kt +++ b/src/main/kotlin/features/mining/HotmPresets.kt @@ -34,9 +34,6 @@ import moe.nea.firmament.util.unformattedString import moe.nea.firmament.util.useMatch object HotmPresets { - object Config : ManagedConfig("hotm-presets", Category.MINING) { - } - val SHARE_PREFIX = "FIRMHOTM/" @Serializable diff --git a/src/main/kotlin/repo/HypixelStaticData.kt b/src/main/kotlin/repo/HypixelStaticData.kt index 5c2a2fc..727a962 100644 --- a/src/main/kotlin/repo/HypixelStaticData.kt +++ b/src/main/kotlin/repo/HypixelStaticData.kt @@ -1,5 +1,3 @@ - - package moe.nea.firmament.repo import io.ktor.client.call.body @@ -21,87 +19,93 @@ import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.async.waitForInput object HypixelStaticData { - private val logger = LogManager.getLogger("Firmament.HypixelStaticData") - private val moulberryBaseUrl = "https://moulberry.codes" - private val hypixelApiBaseUrl = "https://api.hypixel.net" - var lowestBin: Map<SkyblockId, Double> = mapOf() - private set - var bazaarData: Map<SkyblockId, BazaarData> = mapOf() - private set - var collectionData: Map<String, CollectionSkillData> = mapOf() - private set + private val logger = LogManager.getLogger("Firmament.HypixelStaticData") + private val moulberryBaseUrl = "https://moulberry.codes" + private val hypixelApiBaseUrl = "https://api.hypixel.net" + var lowestBin: Map<SkyblockId, Double> = mapOf() + private set + var bazaarData: Map<SkyblockId, BazaarData> = mapOf() + private set + var collectionData: Map<String, CollectionSkillData> = mapOf() + private set + + @Serializable + data class BazaarData( + @SerialName("product_id") + val productId: SkyblockId.BazaarStock, + @SerialName("quick_status") + val quickStatus: BazaarStatus, + ) - @Serializable - data class BazaarData( - @SerialName("product_id") - val productId: SkyblockId.BazaarStock, - @SerialName("quick_status") - val quickStatus: BazaarStatus, - ) + @Serializable + data class BazaarStatus( + val sellPrice: Double, + val sellVolume: Long, + val sellMovingWeek: Long, + val sellOrders: Long, + val buyPrice: Double, + val buyVolume: Long, + val buyMovingWeek: Long, + val buyOrders: Long + ) - @Serializable - data class BazaarStatus( - val sellPrice: Double, - val sellVolume: Long, - val sellMovingWeek: Long, - val sellOrders: Long, - val buyPrice: Double, - val buyVolume: Long, - val buyMovingWeek: Long, - val buyOrders: Long - ) + @Serializable + private data class BazaarResponse( + val success: Boolean, + val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(), + ) - @Serializable - private data class BazaarResponse( - val success: Boolean, - val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(), - ) + fun getPriceOfItem(item: SkyblockId): Double? = bazaarData[item]?.quickStatus?.buyPrice ?: lowestBin[item] - fun getPriceOfItem(item: SkyblockId): Double? = bazaarData[item]?.quickStatus?.buyPrice ?: lowestBin[item] + fun hasBazaarStock(item: SkyblockId): Boolean { + return item in bazaarData + } + fun hasAuctionHouseOffers(item: SkyblockId): Boolean { + return (item in lowestBin) // TODO: || (item in biddableAuctionPrices) + } - fun spawnDataCollectionLoop() { - Firmament.coroutineScope.launch { - logger.info("Updating collection data") - updateCollectionData() - } - Firmament.coroutineScope.launch { - while (true) { - logger.info("Updating NEU prices") - updatePrices() - withTimeoutOrNull(10.minutes) { waitForInput(IKeyBinding.ofKeyCode(GLFW.GLFW_KEY_U)) } - } - } - } + fun spawnDataCollectionLoop() { + Firmament.coroutineScope.launch { + logger.info("Updating collection data") + updateCollectionData() + } + Firmament.coroutineScope.launch { + while (true) { + logger.info("Updating NEU prices") + updatePrices() + } + } + } - private suspend fun updatePrices() { - awaitAll( - Firmament.coroutineScope.async { fetchBazaarPrices() }, - Firmament.coroutineScope.async { fetchPricesFromMoulberry() }, - ) - } + private suspend fun updatePrices() { + awaitAll( + Firmament.coroutineScope.async { fetchBazaarPrices() }, + Firmament.coroutineScope.async { fetchPricesFromMoulberry() }, + ) + } - private suspend fun fetchPricesFromMoulberry() { - lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json") - .body<Map<SkyblockId, Double>>() - } + private suspend fun fetchPricesFromMoulberry() { + lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json") + .body<Map<SkyblockId, Double>>() + } - private suspend fun fetchBazaarPrices() { - val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>() - if (!response.success) { - logger.warn("Retrieved unsuccessful bazaar data") - } - bazaarData = response.products.mapKeys { it.key.toRepoId() } - } + private suspend fun fetchBazaarPrices() { + val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>() + if (!response.success) { + logger.warn("Retrieved unsuccessful bazaar data") + } + bazaarData = response.products.mapKeys { it.key.toRepoId() } + } - private suspend fun updateCollectionData() { - val response = - Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>() - if (!response.success) { - logger.warn("Retrieved unsuccessful collection data") - } - collectionData = response.collections - logger.info("Downloaded ${collectionData.values.sumOf { it.items.values.size }} collections") - } + private suspend fun updateCollectionData() { + val response = + Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>() + if (!response.success) { + logger.warn("Retrieved unsuccessful collection data") + } + collectionData = response.collections + logger.info("Downloaded ${collectionData.values.sumOf { it.items.values.size }} collections") + } } diff --git a/src/main/kotlin/repo/ItemCache.kt b/src/main/kotlin/repo/ItemCache.kt index 6fb2ab8..014de7d 100644 --- a/src/main/kotlin/repo/ItemCache.kt +++ b/src/main/kotlin/repo/ItemCache.kt @@ -23,6 +23,7 @@ import net.minecraft.item.Items import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtElement import net.minecraft.nbt.NbtOps +import net.minecraft.nbt.NbtString import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.gui.config.HudMeta @@ -33,11 +34,11 @@ import moe.nea.firmament.util.LegacyTagParser import moe.nea.firmament.util.MC import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.TestUtil +import moe.nea.firmament.util.mc.FirmamentDataComponentTypes import moe.nea.firmament.util.mc.appendLore import moe.nea.firmament.util.mc.modifyLore import moe.nea.firmament.util.mc.setCustomName import moe.nea.firmament.util.mc.setSkullOwner -import moe.nea.firmament.util.skyblockId object ItemCache : IReloadable { private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap() @@ -67,6 +68,8 @@ object ItemCache : IReloadable { null } + val ItemStack.isBroken + get() = get(FirmamentDataComponentTypes.IS_BROKEN) ?: false fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack { return ItemStack(Items.PAINTING).apply { setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null")) @@ -78,6 +81,10 @@ object ItemCache : IReloadable { ) ) ) + set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(NbtCompound().apply { + put("ID", NbtString.of(neuItem?.skyblockItemId ?: idHint?.neuItem ?: "null")) + })) + set(FirmamentDataComponentTypes.IS_BROKEN, true) } } diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt index 3f5d633..f7c81da 100644 --- a/src/main/kotlin/util/MC.kt +++ b/src/main/kotlin/util/MC.kt @@ -49,6 +49,7 @@ object MC { messageQueue.add(text) } + @Deprecated("Use checked method instead", replaceWith = ReplaceWith("sendCommand(command)")) fun sendServerCommand(command: String) { val nh = player?.networkHandler ?: return nh.sendPacket( diff --git a/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt b/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt new file mode 100644 index 0000000..012f52e --- /dev/null +++ b/src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt @@ -0,0 +1,36 @@ +package moe.nea.firmament.util.mc + +import com.mojang.serialization.Codec +import net.minecraft.component.ComponentType +import net.minecraft.registry.Registries +import net.minecraft.registry.Registry +import moe.nea.firmament.Firmament +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.ClientInitEvent + +object FirmamentDataComponentTypes { + + @Subscribe + fun init(event: ClientInitEvent) { + } + + private fun <T> register( + id: String, + builderOperator: (ComponentType.Builder<T>) -> Unit + ): ComponentType<T> { + return Registry.register( + Registries.DATA_COMPONENT_TYPE, + Firmament.identifier(id), + ComponentType.builder<T>().also(builderOperator) + .build() + ) + } + + val IS_BROKEN = register<Boolean>( + "is_broken" + ) { + it.codec(Codec.BOOL.fieldOf("is_broken").codec()) + } + + +} diff --git a/src/main/kotlin/util/skyblock/SBItemUtil.kt b/src/main/kotlin/util/skyblock/SBItemUtil.kt new file mode 100644 index 0000000..3901b60 --- /dev/null +++ b/src/main/kotlin/util/skyblock/SBItemUtil.kt @@ -0,0 +1,21 @@ +package moe.nea.firmament.util.skyblock + +import net.minecraft.item.ItemStack +import moe.nea.firmament.util.mc.loreAccordingToNbt +import moe.nea.firmament.util.unformattedString + +object SBItemUtil { + fun ItemStack.getSearchName(): String { + val name = this.name.unformattedString + if (name.contains("Enchanted Book")) { + val enchant = loreAccordingToNbt.firstOrNull()?.unformattedString + if (enchant != null) return enchant + } + if (name.startsWith("[Lvl")) { + val closing = name.indexOf(']') + if (closing > 0) + return name.substring(closing) + } + return name + } +} |