Add price checker
This commit is contained in:
@@ -100,6 +100,8 @@ dependencies {
|
|||||||
transInclude(nonModImplentation(ktor("client-java"))!!)
|
transInclude(nonModImplentation(ktor("client-java"))!!)
|
||||||
transInclude(nonModImplentation(ktor("serialization-kotlinx-json"))!!)
|
transInclude(nonModImplentation(ktor("serialization-kotlinx-json"))!!)
|
||||||
transInclude(nonModImplentation(ktor("client-content-negotiation"))!!)
|
transInclude(nonModImplentation(ktor("client-content-negotiation"))!!)
|
||||||
|
transInclude(nonModImplentation(ktor("client-encoding"))!!)
|
||||||
|
transInclude(nonModImplentation(ktor("client-logging"))!!)
|
||||||
|
|
||||||
// Dev environment preinstalled mods
|
// Dev environment preinstalled mods
|
||||||
modRuntimeOnly(libs.bundles.runtime.required)
|
modRuntimeOnly(libs.bundles.runtime.required)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ modmenu = "6.2.1"
|
|||||||
ktor = "2.3.0"
|
ktor = "2.3.0"
|
||||||
dbus_java = "4.2.1"
|
dbus_java = "4.2.1"
|
||||||
architectury = "8.1.79"
|
architectury = "8.1.79"
|
||||||
neurepoparser = "0.0.1"
|
neurepoparser = "1.1.0"
|
||||||
qolify = "1.2.2-1.19.4"
|
qolify = "1.2.2-1.19.4"
|
||||||
citresewn = "1.1.3+1.19.4"
|
citresewn = "1.1.3+1.19.4"
|
||||||
ncr = "Fabric-1.19.4-v2.1.1"
|
ncr = "Fabric-1.19.4-v2.1.1"
|
||||||
|
|||||||
@@ -19,11 +19,14 @@
|
|||||||
package moe.nea.firmament
|
package moe.nea.firmament
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
import io.ktor.client.*
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.plugins.*
|
import io.ktor.client.plugins.UserAgent
|
||||||
import io.ktor.client.plugins.contentnegotiation.*
|
import io.ktor.client.plugins.cache.HttpCache
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.client.plugins.compression.ContentEncoding
|
||||||
import java.awt.Taskbar.Feature
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
|
import io.ktor.client.plugins.logging.LogLevel
|
||||||
|
import io.ktor.client.plugins.logging.Logging
|
||||||
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import net.fabricmc.api.ClientModInitializer
|
import net.fabricmc.api.ClientModInitializer
|
||||||
@@ -35,14 +38,21 @@ import net.fabricmc.loader.api.FabricLoader
|
|||||||
import net.fabricmc.loader.api.Version
|
import net.fabricmc.loader.api.Version
|
||||||
import net.fabricmc.loader.api.metadata.ModMetadata
|
import net.fabricmc.loader.api.metadata.ModMetadata
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.apache.logging.log4j.Logger
|
||||||
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
|
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.CoroutineName
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
import net.minecraft.command.CommandRegistryAccess
|
import net.minecraft.command.CommandRegistryAccess
|
||||||
import moe.nea.firmament.commands.registerFirmamentCommand
|
import moe.nea.firmament.commands.registerFirmamentCommand
|
||||||
import moe.nea.firmament.dbus.FirmamentDbusObject
|
import moe.nea.firmament.dbus.FirmamentDbusObject
|
||||||
import moe.nea.firmament.features.FeatureManager
|
import moe.nea.firmament.features.FeatureManager
|
||||||
|
import moe.nea.firmament.repo.ItemCostData
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
import moe.nea.firmament.util.SBData
|
import moe.nea.firmament.util.SBData
|
||||||
import moe.nea.firmament.util.data.IDataHolder
|
import moe.nea.firmament.util.data.IDataHolder
|
||||||
@@ -53,8 +63,10 @@ object Firmament : ModInitializer, ClientModInitializer {
|
|||||||
val DEBUG = System.getProperty("firmament.debug") == "true"
|
val DEBUG = System.getProperty("firmament.debug") == "true"
|
||||||
val DATA_DIR: Path = Path.of(".firmament").also { Files.createDirectories(it) }
|
val DATA_DIR: Path = Path.of(".firmament").also { Files.createDirectories(it) }
|
||||||
val CONFIG_DIR: Path = Path.of("config/firmament").also { Files.createDirectories(it) }
|
val CONFIG_DIR: Path = Path.of("config/firmament").also { Files.createDirectories(it) }
|
||||||
val logger = LogManager.getLogger("Firmament")
|
val logger: Logger = LogManager.getLogger("Firmament")
|
||||||
val metadata: ModMetadata by lazy { FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().metadata }
|
private val metadata: ModMetadata by lazy {
|
||||||
|
FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow().metadata
|
||||||
|
}
|
||||||
val version: Version by lazy { metadata.version }
|
val version: Version by lazy { metadata.version }
|
||||||
|
|
||||||
val json = Json {
|
val json = Json {
|
||||||
@@ -68,9 +80,18 @@ object Firmament : ModInitializer, ClientModInitializer {
|
|||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json(json)
|
json(json)
|
||||||
}
|
}
|
||||||
|
install(ContentEncoding) {
|
||||||
|
gzip()
|
||||||
|
deflate()
|
||||||
|
}
|
||||||
install(UserAgent) {
|
install(UserAgent) {
|
||||||
agent = "Firmament/$version"
|
agent = "Firmament/$version"
|
||||||
}
|
}
|
||||||
|
if (DEBUG)
|
||||||
|
install(Logging) {
|
||||||
|
level = LogLevel.INFO
|
||||||
|
}
|
||||||
|
install(HttpCache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +119,7 @@ object Firmament : ModInitializer, ClientModInitializer {
|
|||||||
RepoManager.initialize()
|
RepoManager.initialize()
|
||||||
SBData.init()
|
SBData.init()
|
||||||
FeatureManager.autoload()
|
FeatureManager.autoload()
|
||||||
|
ItemCostData.spawnPriceLoop()
|
||||||
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
|
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
|
||||||
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.mojang.brigadier.builder.ArgumentBuilder
|
|||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder
|
||||||
import com.mojang.brigadier.context.CommandContext
|
import com.mojang.brigadier.context.CommandContext
|
||||||
|
import com.mojang.brigadier.suggestion.SuggestionProvider
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||||
import moe.nea.firmament.util.iterate
|
import moe.nea.firmament.util.iterate
|
||||||
@@ -80,6 +81,17 @@ fun <T : ArgumentBuilder<DefaultSource, T>, AT : Any> T.thenArgument(
|
|||||||
block: RequiredArgumentBuilder<DefaultSource, AT>.(TypeSafeArg<AT>) -> Unit
|
block: RequiredArgumentBuilder<DefaultSource, AT>.(TypeSafeArg<AT>) -> Unit
|
||||||
): T = then(argument(name, argument, block))
|
): T = then(argument(name, argument, block))
|
||||||
|
|
||||||
|
fun <T : RequiredArgumentBuilder<DefaultSource, String>> T.suggestsList(provider: () -> Iterable<String>) {
|
||||||
|
suggests(SuggestionProvider<DefaultSource> { context, builder ->
|
||||||
|
provider()
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.startsWith(builder.remaining, ignoreCase = true) }
|
||||||
|
.forEach {
|
||||||
|
builder.suggest(it)
|
||||||
|
}
|
||||||
|
builder.buildFuture()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fun <T : ArgumentBuilder<DefaultSource, T>> T.thenLiteral(
|
fun <T : ArgumentBuilder<DefaultSource, T>> T.thenLiteral(
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
@@ -19,12 +19,16 @@
|
|||||||
package moe.nea.firmament.commands
|
package moe.nea.firmament.commands
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher
|
import com.mojang.brigadier.CommandDispatcher
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType.getString
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType.string
|
||||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import moe.nea.firmament.features.world.FairySouls
|
import moe.nea.firmament.features.world.FairySouls
|
||||||
import moe.nea.firmament.gui.config.AllConfigsGui
|
import moe.nea.firmament.gui.config.AllConfigsGui
|
||||||
|
import moe.nea.firmament.repo.ItemCostData
|
||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
import moe.nea.firmament.util.SBData
|
import moe.nea.firmament.util.SBData
|
||||||
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
|
||||||
|
|
||||||
fun firmamentCommand() = literal("firmament") {
|
fun firmamentCommand() = literal("firmament") {
|
||||||
@@ -47,6 +51,28 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
thenLiteral("price") {
|
||||||
|
thenArgument("item", string()) { item ->
|
||||||
|
suggestsList { RepoManager.neuRepo.items.items.keys }
|
||||||
|
thenExecute {
|
||||||
|
val itemName = SkyblockId(getString(context, "item"))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price", itemName.neuItem))
|
||||||
|
val bazaarData = ItemCostData.bazaarData[itemName]
|
||||||
|
if (bazaarData != null) {
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar"))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar.buy.price", bazaarData.quickStatus.buyPrice))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar.buy.order", bazaarData.quickStatus.buyOrders))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar.sell.price", bazaarData.quickStatus.sellPrice))
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.bazaar.sell.order", bazaarData.quickStatus.sellOrders))
|
||||||
|
}
|
||||||
|
val lowestBin = ItemCostData.lowestBin[itemName]
|
||||||
|
if (lowestBin != null) {
|
||||||
|
source.sendFeedback(Text.translatable("firmament.price.lowestbin", lowestBin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
thenLiteral("dev") {
|
thenLiteral("dev") {
|
||||||
thenLiteral("config") {
|
thenLiteral("config") {
|
||||||
thenExecute {
|
thenExecute {
|
||||||
|
|||||||
@@ -19,10 +19,16 @@
|
|||||||
package moe.nea.firmament.events
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
import net.minecraft.client.option.KeyBinding
|
import net.minecraft.client.option.KeyBinding
|
||||||
|
import moe.nea.firmament.keybindings.IKeyBinding
|
||||||
|
|
||||||
data class HandledScreenKeyPressedEvent(val keyCode: Int, val scanCode: Int, val modifiers: Int) : FirmamentEvent.Cancellable() {
|
data class HandledScreenKeyPressedEvent(val keyCode: Int, val scanCode: Int, val modifiers: Int) : FirmamentEvent.Cancellable() {
|
||||||
companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>()
|
companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>()
|
||||||
|
|
||||||
fun matches(keyBinding: KeyBinding): Boolean {
|
fun matches(keyBinding: KeyBinding): Boolean {
|
||||||
return keyBinding.matchesKey(keyCode, scanCode)
|
return matches(IKeyBinding.minecraft(keyBinding))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun matches(keyBinding: IKeyBinding): Boolean {
|
||||||
|
return keyBinding.matches(keyCode, scanCode, modifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/main/kotlin/moe/nea/firmament/events/TooltipEvent.kt
Normal file
15
src/main/kotlin/moe/nea/firmament/events/TooltipEvent.kt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.tooltip.Tooltip
|
||||||
|
import net.minecraft.client.item.TooltipContext
|
||||||
|
import net.minecraft.entity.player.PlayerEntity
|
||||||
|
import net.minecraft.item.ItemStack
|
||||||
|
|
||||||
|
data class TooltipEvent(
|
||||||
|
val itemStack: ItemStack,
|
||||||
|
val tooltip: Tooltip,
|
||||||
|
val tooltipContext: TooltipContext,
|
||||||
|
val player: PlayerEntity?
|
||||||
|
) : FirmamentEvent() {
|
||||||
|
companion object : FirmamentEventBus<TooltipEvent>()
|
||||||
|
}
|
||||||
27
src/main/kotlin/moe/nea/firmament/keybindings/IKeyBinding.kt
Normal file
27
src/main/kotlin/moe/nea/firmament/keybindings/IKeyBinding.kt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package moe.nea.firmament.keybindings
|
||||||
|
|
||||||
|
import net.minecraft.client.option.KeyBinding
|
||||||
|
|
||||||
|
interface IKeyBinding {
|
||||||
|
fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean
|
||||||
|
|
||||||
|
fun withModifiers(wantedModifiers: Int): IKeyBinding {
|
||||||
|
val old = this
|
||||||
|
return object : IKeyBinding {
|
||||||
|
override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||||
|
return old.matches(keyCode, scanCode, modifiers) && (modifiers and wantedModifiers) == wantedModifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun minecraft(keyBinding: KeyBinding) = object : IKeyBinding {
|
||||||
|
override fun matches(keyCode: Int, scanCode: Int, modifiers: Int) =
|
||||||
|
keyBinding.matchesKey(keyCode, scanCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ofKeyCode(wantedKeyCode: Int) = object : IKeyBinding {
|
||||||
|
override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean = keyCode == wantedKeyCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -106,7 +106,7 @@ object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
|
|||||||
getEntry(SBItemStack(skyblockId, RepoManager.getNEUItem(skyblockId), count))
|
getEntry(SBItemStack(skyblockId, RepoManager.getNEUItem(skyblockId), count))
|
||||||
|
|
||||||
fun getEntry(ingredient: NEUIngredient): EntryStack<SBItemStack> =
|
fun getEntry(ingredient: NEUIngredient): EntryStack<SBItemStack> =
|
||||||
getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount)
|
getEntry(SkyblockId(ingredient.itemId), count = ingredient.amount.toInt())
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
86
src/main/kotlin/moe/nea/firmament/repo/ItemCostData.kt
Normal file
86
src/main/kotlin/moe/nea/firmament/repo/ItemCostData.kt
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package moe.nea.firmament.repo
|
||||||
|
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.lwjgl.glfw.GLFW
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.keybindings.IKeyBinding
|
||||||
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.async.waitForInput
|
||||||
|
|
||||||
|
object ItemCostData {
|
||||||
|
private val logger = LogManager.getLogger("Firmament.ItemCostData")
|
||||||
|
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
|
||||||
|
|
||||||
|
@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
|
||||||
|
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 spawnPriceLoop() {
|
||||||
|
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() {
|
||||||
|
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 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() }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -27,11 +27,36 @@ import net.minecraft.item.ItemStack
|
|||||||
import net.minecraft.nbt.NbtCompound
|
import net.minecraft.nbt.NbtCompound
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A skyblock item id, as used by the NEU repo.
|
||||||
|
* This is not exactly the format used by HyPixel, but is mostly the same.
|
||||||
|
* Usually this id splits an id used by HyPixel into more sub items. For example `PET` becomes `$PET_ID;$PET_RARITY`,
|
||||||
|
* with those values extracted from other metadata.
|
||||||
|
*/
|
||||||
@JvmInline
|
@JvmInline
|
||||||
|
@Serializable
|
||||||
value class SkyblockId(val neuItem: String) {
|
value class SkyblockId(val neuItem: String) {
|
||||||
val identifier get() = Identifier("skyblockitem", neuItem.lowercase().replace(";", "__"))
|
val identifier get() = Identifier("skyblockitem", neuItem.lowercase().replace(";", "__"))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A bazaar stock item id, as returned by the HyPixel bazaar api endpoint.
|
||||||
|
* These are not equivalent to the in-game ids, or the NEU repo ids, and in fact, do not refer to items, but instead
|
||||||
|
* to bazaar stocks. The main difference from [SkyblockId]s is concerning enchanted books. There are probably more,
|
||||||
|
* but for now this holds.
|
||||||
|
*/
|
||||||
|
@JvmInline
|
||||||
|
@Serializable
|
||||||
|
value class BazaarStock(val bazaarId: String) {
|
||||||
|
fun toRepoId(): SkyblockId {
|
||||||
|
bazaarEnchantmentRegex.matchEntire(bazaarId)?.let {
|
||||||
|
return SkyblockId("${it.groupValues[1]};${it.groupValues[2]}")
|
||||||
|
}
|
||||||
|
return SkyblockId(bazaarId.replace(":", "-"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val bazaarEnchantmentRegex = "ENCHANTMENT_(\\D*)_(\\d+)".toRegex()
|
||||||
val NULL: SkyblockId = SkyblockId("null")
|
val NULL: SkyblockId = SkyblockId("null")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/main/kotlin/moe/nea/firmament/util/async/input.kt
Normal file
45
src/main/kotlin/moe/nea/firmament/util/async/input.kt
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package moe.nea.firmament.util.async
|
||||||
|
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
|
||||||
|
import moe.nea.firmament.keybindings.IKeyBinding
|
||||||
|
|
||||||
|
private object InputHandler {
|
||||||
|
data class KeyInputContinuation(val keybind: IKeyBinding, val onContinue: () -> Unit)
|
||||||
|
|
||||||
|
private val activeContinuations = mutableListOf<KeyInputContinuation>()
|
||||||
|
|
||||||
|
fun registerContinuation(keyInputContinuation: KeyInputContinuation): () -> Unit {
|
||||||
|
synchronized(InputHandler) {
|
||||||
|
activeContinuations.add(keyInputContinuation)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
synchronized(this) {
|
||||||
|
activeContinuations.remove(keyInputContinuation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
HandledScreenKeyPressedEvent.subscribe { event ->
|
||||||
|
synchronized(InputHandler) {
|
||||||
|
val toRemove = activeContinuations.filter {
|
||||||
|
event.matches(it.keybind)
|
||||||
|
}
|
||||||
|
toRemove.forEach { it.onContinue() }
|
||||||
|
activeContinuations.removeAll(toRemove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun waitForInput(keybind: IKeyBinding): Unit = suspendCancellableCoroutine { cont ->
|
||||||
|
val unregister =
|
||||||
|
InputHandler.registerContinuation(InputHandler.KeyInputContinuation(keybind) { cont.resume(Unit) })
|
||||||
|
cont.invokeOnCancellation {
|
||||||
|
unregister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,21 +1,12 @@
|
|||||||
/**
|
|
||||||
* Firmament is a Hypixel Skyblock mod for modern Minecraft versions
|
|
||||||
* Copyright (C) 2023 Linnea Gräf
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
|
"firmament.price": "Checking price for %s",
|
||||||
|
"firmament.price.bazaar": "Bazaar stats:",
|
||||||
|
"firmament.price.bazaar.productid": "Stock id: %s",
|
||||||
|
"firmament.price.bazaar.buy.price": "Buy Price: %.1f",
|
||||||
|
"firmament.price.bazaar.buy.order": "Buy orders: %d",
|
||||||
|
"firmament.price.bazaar.sell.price": "Sell Price: %.1f",
|
||||||
|
"firmament.price.bazaar.sell.order": "Sell orders: %d",
|
||||||
|
"firmament.price.lowestbin": "Lowest BIN: %.1f",
|
||||||
"firmament.repo.reload.network": "Trying to redownload the repository",
|
"firmament.repo.reload.network": "Trying to redownload the repository",
|
||||||
"firmament.repo.reload.disk": "Reloading repository from disk. This may lag a bit.",
|
"firmament.repo.reload.disk": "Reloading repository from disk. This may lag a bit.",
|
||||||
"firmament.repo.cache": "Recaching items",
|
"firmament.repo.cache": "Recaching items",
|
||||||
|
|||||||
Reference in New Issue
Block a user