package moe.nea.firmament.features.mining import io.github.notenoughupdates.moulconfig.xml.Bind import moe.nea.jarvis.api.Point import kotlinx.serialization.Serializable import kotlinx.serialization.serializer import kotlin.time.Duration.Companion.seconds import net.minecraft.text.Text import moe.nea.firmament.annotations.Subscribe import moe.nea.firmament.events.ProcessChatEvent import moe.nea.firmament.features.FirmamentFeature import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.gui.hud.MoulConfigHud import moe.nea.firmament.util.BazaarPriceStrategy import moe.nea.firmament.util.FirmFormatters.formatCommas import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.data.ProfileSpecificDataHolder import moe.nea.firmament.util.formattedString import moe.nea.firmament.util.parseIntWithComma import moe.nea.firmament.util.useMatch object PristineProfitTracker : FirmamentFeature { override val identifier: String get() = "pristine-profit" enum class GemstoneKind( val label: String, val flawedId: SkyblockId, ) { SAPPHIRE("Sapphire", SkyblockId("FLAWED_SAPPHIRE_GEM")), RUBY("Ruby", SkyblockId("FLAWED_RUBY_GEM")), AMETHYST("Amethyst", SkyblockId("FLAWED_AMETHYST_GEM")), AMBER("Amber", SkyblockId("FLAWED_AMBER_GEM")), TOPAZ("Topaz", SkyblockId("FLAWED_TOPAZ_GEM")), JADE("Jade", SkyblockId("FLAWED_JADE_GEM")), JASPER("Jasper", SkyblockId("FLAWED_JASPER_GEM")), OPAL("Opal", SkyblockId("FLAWED_OPAL_GEM")), } @Serializable data class Data( var maxMoneyPerSecond: Double = 1.0, var maxCollectionPerSecond: Double = 1.0, ) object DConfig : ProfileSpecificDataHolder(serializer(), identifier, ::Data) override val config: ManagedConfig? get() = TConfig object TConfig : ManagedConfig(identifier, Category.MINING) { val timeout by duration("timeout", 0.seconds, 120.seconds) { 30.seconds } val gui by position("position", 80, 30) { Point(0.05, 0.2) } } val sellingStrategy = BazaarPriceStrategy.SELL_ORDER val pristineRegex = "PRISTINE! You found . Flawed (?${ GemstoneKind.entries.joinToString("|") { it.label } }) Gemstone x(?[0-9,]+)!".toPattern() val collectionHistogram = Histogram(10000, 180.seconds) val moneyHistogram = Histogram(10000, 180.seconds) object ProfitHud : MoulConfigHud("pristine_profit", TConfig.gui) { @field:Bind var moneyCurrent: Double = 0.0 @field:Bind var moneyMax: Double = 1.0 @field:Bind var moneyText = "" @field:Bind var collectionCurrent = 0.0 @field:Bind var collectionMax = 1.0 @field:Bind var collectionText = "" override fun shouldRender(): Boolean = collectionHistogram.latestUpdate().passedTime() < TConfig.timeout } val SECONDS_PER_HOUR = 3600 val ROUGHS_PER_FLAWED = 80 fun updateUi() { val collectionPerSecond = collectionHistogram.averagePer({ it }, 1.seconds) val moneyPerSecond = moneyHistogram.averagePer({ it }, 1.seconds) if (collectionPerSecond == null || moneyPerSecond == null) return ProfitHud.collectionCurrent = collectionPerSecond ProfitHud.collectionText = Text.stringifiedTranslatable("firmament.pristine-profit.collection", formatCommas(collectionPerSecond * SECONDS_PER_HOUR, 1)).formattedString() ProfitHud.moneyCurrent = moneyPerSecond ProfitHud.moneyText = Text.stringifiedTranslatable("firmament.pristine-profit.money", formatCommas(moneyPerSecond * SECONDS_PER_HOUR, 1)) .formattedString() val data = DConfig.data if (data != null) { if (data.maxCollectionPerSecond < collectionPerSecond && collectionHistogram.oldestUpdate() .passedTime() > 30.seconds ) { data.maxCollectionPerSecond = collectionPerSecond DConfig.markDirty() } if (data.maxMoneyPerSecond < moneyPerSecond && moneyHistogram.oldestUpdate().passedTime() > 30.seconds) { data.maxMoneyPerSecond = moneyPerSecond DConfig.markDirty() } ProfitHud.collectionMax = maxOf(data.maxCollectionPerSecond, collectionPerSecond) ProfitHud.moneyMax = maxOf(data.maxMoneyPerSecond, moneyPerSecond) } } @Subscribe fun onMessage(it: ProcessChatEvent) { pristineRegex.useMatch(it.unformattedString) { val gemstoneKind = GemstoneKind.valueOf(group("kind").uppercase()) val flawedCount = parseIntWithComma(group("count")) val moneyAmount = sellingStrategy.getSellPrice(gemstoneKind.flawedId) * flawedCount moneyHistogram.record(moneyAmount) val collectionAmount = flawedCount * ROUGHS_PER_FLAWED collectionHistogram.record(collectionAmount.toDouble()) updateUi() } } }