feat: Add bazaar/ah search hotkey
This commit is contained in:
@@ -35,6 +35,7 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||||||
import net.minecraft.command.CommandRegistryAccess
|
import net.minecraft.command.CommandRegistryAccess
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import moe.nea.firmament.commands.registerFirmamentCommand
|
import moe.nea.firmament.commands.registerFirmamentCommand
|
||||||
|
import moe.nea.firmament.events.ClientInitEvent
|
||||||
import moe.nea.firmament.events.ClientStartedEvent
|
import moe.nea.firmament.events.ClientStartedEvent
|
||||||
import moe.nea.firmament.events.CommandEvent
|
import moe.nea.firmament.events.CommandEvent
|
||||||
import moe.nea.firmament.events.ItemTooltipEvent
|
import moe.nea.firmament.events.ItemTooltipEvent
|
||||||
@@ -141,6 +142,7 @@ object Firmament {
|
|||||||
ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext))
|
ScreenRenderPostEvent.publish(ScreenRenderPostEvent(screen, mouseX, mouseY, tickDelta, drawContext))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
ClientInitEvent.publish(ClientInitEvent())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
src/main/kotlin/events/ClientInitEvent.kt
Normal file
5
src/main/kotlin/events/ClientInitEvent.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
class ClientInitEvent : FirmamentEvent() {
|
||||||
|
companion object : FirmamentEventBus<ClientInitEvent>()
|
||||||
|
}
|
||||||
@@ -90,6 +90,9 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
|||||||
fun subscribeEvents() {
|
fun subscribeEvents() {
|
||||||
SubscriptionList.allLists.forEach {
|
SubscriptionList.allLists.forEach {
|
||||||
it.provideSubscriptions {
|
it.provideSubscriptions {
|
||||||
|
it.owner.javaClass.classes.forEach {
|
||||||
|
runCatching { it.getDeclaredField("INSTANCE").get(null) }
|
||||||
|
}
|
||||||
subscribeSingleEvent(it)
|
subscribeSingleEvent(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/main/kotlin/features/inventory/ItemHotkeys.kt
Normal file
39
src/main/kotlin/features/inventory/ItemHotkeys.kt
Normal file
@@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,9 +34,6 @@ import moe.nea.firmament.util.unformattedString
|
|||||||
import moe.nea.firmament.util.useMatch
|
import moe.nea.firmament.util.useMatch
|
||||||
|
|
||||||
object HotmPresets {
|
object HotmPresets {
|
||||||
object Config : ManagedConfig("hotm-presets", Category.MINING) {
|
|
||||||
}
|
|
||||||
|
|
||||||
val SHARE_PREFIX = "FIRMHOTM/"
|
val SHARE_PREFIX = "FIRMHOTM/"
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
package moe.nea.firmament.repo
|
package moe.nea.firmament.repo
|
||||||
|
|
||||||
import io.ktor.client.call.body
|
import io.ktor.client.call.body
|
||||||
@@ -21,87 +19,93 @@ import moe.nea.firmament.util.SkyblockId
|
|||||||
import moe.nea.firmament.util.async.waitForInput
|
import moe.nea.firmament.util.async.waitForInput
|
||||||
|
|
||||||
object HypixelStaticData {
|
object HypixelStaticData {
|
||||||
private val logger = LogManager.getLogger("Firmament.HypixelStaticData")
|
private val logger = LogManager.getLogger("Firmament.HypixelStaticData")
|
||||||
private val moulberryBaseUrl = "https://moulberry.codes"
|
private val moulberryBaseUrl = "https://moulberry.codes"
|
||||||
private val hypixelApiBaseUrl = "https://api.hypixel.net"
|
private val hypixelApiBaseUrl = "https://api.hypixel.net"
|
||||||
var lowestBin: Map<SkyblockId, Double> = mapOf()
|
var lowestBin: Map<SkyblockId, Double> = mapOf()
|
||||||
private set
|
private set
|
||||||
var bazaarData: Map<SkyblockId, BazaarData> = mapOf()
|
var bazaarData: Map<SkyblockId, BazaarData> = mapOf()
|
||||||
private set
|
private set
|
||||||
var collectionData: Map<String, CollectionSkillData> = mapOf()
|
var collectionData: Map<String, CollectionSkillData> = mapOf()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BazaarData(
|
data class BazaarData(
|
||||||
@SerialName("product_id")
|
@SerialName("product_id")
|
||||||
val productId: SkyblockId.BazaarStock,
|
val productId: SkyblockId.BazaarStock,
|
||||||
@SerialName("quick_status")
|
@SerialName("quick_status")
|
||||||
val quickStatus: BazaarStatus,
|
val quickStatus: BazaarStatus,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BazaarStatus(
|
data class BazaarStatus(
|
||||||
val sellPrice: Double,
|
val sellPrice: Double,
|
||||||
val sellVolume: Long,
|
val sellVolume: Long,
|
||||||
val sellMovingWeek: Long,
|
val sellMovingWeek: Long,
|
||||||
val sellOrders: Long,
|
val sellOrders: Long,
|
||||||
val buyPrice: Double,
|
val buyPrice: Double,
|
||||||
val buyVolume: Long,
|
val buyVolume: Long,
|
||||||
val buyMovingWeek: Long,
|
val buyMovingWeek: Long,
|
||||||
val buyOrders: Long
|
val buyOrders: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
private data class BazaarResponse(
|
private data class BazaarResponse(
|
||||||
val success: Boolean,
|
val success: Boolean,
|
||||||
val products: Map<SkyblockId.BazaarStock, BazaarData> = mapOf(),
|
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 spawnDataCollectionLoop() {
|
fun hasAuctionHouseOffers(item: SkyblockId): Boolean {
|
||||||
Firmament.coroutineScope.launch {
|
return (item in lowestBin) // TODO: || (item in biddableAuctionPrices)
|
||||||
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)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updatePrices() {
|
fun spawnDataCollectionLoop() {
|
||||||
awaitAll(
|
Firmament.coroutineScope.launch {
|
||||||
Firmament.coroutineScope.async { fetchBazaarPrices() },
|
logger.info("Updating collection data")
|
||||||
Firmament.coroutineScope.async { fetchPricesFromMoulberry() },
|
updateCollectionData()
|
||||||
)
|
}
|
||||||
}
|
Firmament.coroutineScope.launch {
|
||||||
|
while (true) {
|
||||||
|
logger.info("Updating NEU prices")
|
||||||
|
updatePrices()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun fetchPricesFromMoulberry() {
|
private suspend fun updatePrices() {
|
||||||
lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json")
|
awaitAll(
|
||||||
.body<Map<SkyblockId, Double>>()
|
Firmament.coroutineScope.async { fetchBazaarPrices() },
|
||||||
}
|
Firmament.coroutineScope.async { fetchPricesFromMoulberry() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun fetchBazaarPrices() {
|
private suspend fun fetchPricesFromMoulberry() {
|
||||||
val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>()
|
lowestBin = Firmament.httpClient.get("$moulberryBaseUrl/lowestbin.json")
|
||||||
if (!response.success) {
|
.body<Map<SkyblockId, Double>>()
|
||||||
logger.warn("Retrieved unsuccessful bazaar data")
|
}
|
||||||
}
|
|
||||||
bazaarData = response.products.mapKeys { it.key.toRepoId() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateCollectionData() {
|
private suspend fun fetchBazaarPrices() {
|
||||||
val response =
|
val response = Firmament.httpClient.get("$hypixelApiBaseUrl/skyblock/bazaar").body<BazaarResponse>()
|
||||||
Firmament.httpClient.get("$hypixelApiBaseUrl/resources/skyblock/collections").body<CollectionResponse>()
|
if (!response.success) {
|
||||||
if (!response.success) {
|
logger.warn("Retrieved unsuccessful bazaar data")
|
||||||
logger.warn("Retrieved unsuccessful collection data")
|
}
|
||||||
}
|
bazaarData = response.products.mapKeys { it.key.toRepoId() }
|
||||||
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")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.minecraft.item.Items
|
|||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.nbt.NbtElement
|
import net.minecraft.nbt.NbtElement
|
||||||
import net.minecraft.nbt.NbtOps
|
import net.minecraft.nbt.NbtOps
|
||||||
|
import net.minecraft.nbt.NbtString
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
import moe.nea.firmament.gui.config.HudMeta
|
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.MC
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
import moe.nea.firmament.util.TestUtil
|
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.appendLore
|
||||||
import moe.nea.firmament.util.mc.modifyLore
|
import moe.nea.firmament.util.mc.modifyLore
|
||||||
import moe.nea.firmament.util.mc.setCustomName
|
import moe.nea.firmament.util.mc.setCustomName
|
||||||
import moe.nea.firmament.util.mc.setSkullOwner
|
import moe.nea.firmament.util.mc.setSkullOwner
|
||||||
import moe.nea.firmament.util.skyblockId
|
|
||||||
|
|
||||||
object ItemCache : IReloadable {
|
object ItemCache : IReloadable {
|
||||||
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
|
private val cache: MutableMap<String, ItemStack> = ConcurrentHashMap()
|
||||||
@@ -67,6 +68,8 @@ object ItemCache : IReloadable {
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ItemStack.isBroken
|
||||||
|
get() = get(FirmamentDataComponentTypes.IS_BROKEN) ?: false
|
||||||
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
|
fun brokenItemStack(neuItem: NEUItem?, idHint: SkyblockId? = null): ItemStack {
|
||||||
return ItemStack(Items.PAINTING).apply {
|
return ItemStack(Items.PAINTING).apply {
|
||||||
setCustomName(Text.literal(neuItem?.displayName ?: idHint?.neuItem ?: "null"))
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ object MC {
|
|||||||
messageQueue.add(text)
|
messageQueue.add(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use checked method instead", replaceWith = ReplaceWith("sendCommand(command)"))
|
||||||
fun sendServerCommand(command: String) {
|
fun sendServerCommand(command: String) {
|
||||||
val nh = player?.networkHandler ?: return
|
val nh = player?.networkHandler ?: return
|
||||||
nh.sendPacket(
|
nh.sendPacket(
|
||||||
|
|||||||
36
src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt
Normal file
36
src/main/kotlin/util/mc/FirmamentDataComponentTypes.kt
Normal file
@@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/kotlin/util/skyblock/SBItemUtil.kt
Normal file
21
src/main/kotlin/util/skyblock/SBItemUtil.kt
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,9 @@
|
|||||||
"firmament.config.inventory-buttons": "Inventory buttons",
|
"firmament.config.inventory-buttons": "Inventory buttons",
|
||||||
"firmament.config.inventory-buttons.open-editor": "Open Editor",
|
"firmament.config.inventory-buttons.open-editor": "Open Editor",
|
||||||
"firmament.config.inventory-buttons.open-editor.description": "Click anywhere to create a new inventory button or to edit one. Hold SHIFT to grid align.",
|
"firmament.config.inventory-buttons.open-editor.description": "Click anywhere to create a new inventory button or to edit one. Hold SHIFT to grid align.",
|
||||||
|
"firmament.config.item-hotkeys": "Item Hotkeys",
|
||||||
|
"firmament.config.item-hotkeys.global-trade-interface": "Search on Bazaar/AH",
|
||||||
|
"firmament.config.item-hotkeys.global-trade-interface.description": "Press this button to search the hovered item on the bazaar or auction house.",
|
||||||
"firmament.config.item-rarity-cosmetics": "Item Rarity Cosmetics",
|
"firmament.config.item-rarity-cosmetics": "Item Rarity Cosmetics",
|
||||||
"firmament.config.item-rarity-cosmetics.background": "Slot Background Rarity",
|
"firmament.config.item-rarity-cosmetics.background": "Slot Background Rarity",
|
||||||
"firmament.config.item-rarity-cosmetics.background-hotbar": "Hotbar Background Rarity",
|
"firmament.config.item-rarity-cosmetics.background-hotbar": "Hotbar Background Rarity",
|
||||||
|
|||||||
Reference in New Issue
Block a user