aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-11-17 17:29:15 +0100
committerLinnea Gräf <nea@nea.moe>2024-11-17 17:29:15 +0100
commit970dfddaf9e80d6b206f411139227397f4d9e847 (patch)
tree999f15cf28127c2053058dd877f6354540c22553 /src/main/kotlin
parent915ab96b2444fa2e93d99a9747861b619d77f8f8 (diff)
downloadFirmament-970dfddaf9e80d6b206f411139227397f4d9e847.tar.gz
Firmament-970dfddaf9e80d6b206f411139227397f4d9e847.tar.bz2
Firmament-970dfddaf9e80d6b206f411139227397f4d9e847.zip
feat: Add bazaar/ah search hotkey
Diffstat (limited to 'src/main/kotlin')
-rw-r--r--src/main/kotlin/Firmament.kt2
-rw-r--r--src/main/kotlin/events/ClientInitEvent.kt5
-rw-r--r--src/main/kotlin/features/FeatureManager.kt3
-rw-r--r--src/main/kotlin/features/inventory/ItemHotkeys.kt39
-rw-r--r--src/main/kotlin/features/mining/HotmPresets.kt3
-rw-r--r--src/main/kotlin/repo/HypixelStaticData.kt152
-rw-r--r--src/main/kotlin/repo/ItemCache.kt9
-rw-r--r--src/main/kotlin/util/MC.kt1
-rw-r--r--src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt36
-rw-r--r--src/main/kotlin/util/skyblock/SBItemUtil.kt21
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
+ }
+}