diff options
author | Linnea Gräf <nea@nea.moe> | 2024-06-14 18:34:40 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-06-14 18:34:40 +0200 |
commit | e4bd69a0569b4ccc49b9e4b89998220bf4bfe25a (patch) | |
tree | 2cb89c55c9c63cbb115cfeaff1848f301c9a461c /src/main/kotlin/moe/nea/firmament/features | |
parent | cd1826a49822e7be0fb583e7b540270560fb657d (diff) | |
download | firmament-e4bd69a0569b4ccc49b9e4b89998220bf4bfe25a.tar.gz firmament-e4bd69a0569b4ccc49b9e4b89998220bf4bfe25a.tar.bz2 firmament-e4bd69a0569b4ccc49b9e4b89998220bf4bfe25a.zip |
Add shiny pig tracker
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/features')
3 files changed, 267 insertions, 0 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 4c1fde8..f2b2d25 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -22,6 +22,7 @@ import moe.nea.firmament.features.debug.DeveloperFeatures import moe.nea.firmament.features.debug.MinorTrolling import moe.nea.firmament.features.debug.PowerUserTools import moe.nea.firmament.features.diana.DianaWaypoints +import moe.nea.firmament.features.events.anniversity.AnniversaryFeatures import moe.nea.firmament.features.fixes.CompatibliltyFeatures import moe.nea.firmament.features.fixes.Fixes import moe.nea.firmament.features.inventory.CraftingOverlay @@ -70,6 +71,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature loadFeature(ChatLinks) loadFeature(InventoryButtons) loadFeature(CompatibliltyFeatures) + loadFeature(AnniversaryFeatures) loadFeature(QuickCommands) loadFeature(SaveCursorPosition) loadFeature(CustomSkyBlockTextures) diff --git a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt index d530487..17e8253 100644 --- a/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt +++ b/src/main/kotlin/moe/nea/firmament/features/debug/PowerUserTools.kt @@ -10,12 +10,16 @@ package moe.nea.firmament.features.debug import net.minecraft.block.SkullBlock import net.minecraft.block.entity.SkullBlockEntity import net.minecraft.component.DataComponentTypes +import net.minecraft.entity.Entity +import net.minecraft.entity.LivingEntity import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.text.Text import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.EntityHitResult import net.minecraft.util.hit.HitResult import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.CommandEvent import moe.nea.firmament.events.CustomItemModelEvent import moe.nea.firmament.events.HandledScreenKeyPressedEvent import moe.nea.firmament.events.ItemTooltipEvent @@ -41,6 +45,7 @@ object PowerUserTools : FirmamentFeature { val copyTexturePackId by keyBindingWithDefaultUnbound("copy-texture-pack-id") val copyNbtData by keyBindingWithDefaultUnbound("copy-nbt-data") val copySkullTexture by keyBindingWithDefaultUnbound("copy-skull-texture") + val copyEntityData by keyBindingWithDefaultUnbound("entity-data") } override val config @@ -65,6 +70,37 @@ object PowerUserTools : FirmamentFeature { } } + fun debugFormat(itemStack: ItemStack): Text { + return Text.literal(itemStack.skyBlockId?.toString() ?: itemStack.toString()) + } + + @Subscribe + fun onEntityInfo(event: WorldKeyboardEvent) { + if (!event.matches(TConfig.copyEntityData)) return + val target = (MC.instance.crosshairTarget as? EntityHitResult)?.entity + if (target == null) { + MC.sendChat(Text.translatable("firmament.poweruser.entity.fail")) + return + } + showEntity(target) + } + + fun showEntity(target: Entity) { + MC.sendChat(Text.translatable("firmament.poweruser.entity.type", target.type)) + MC.sendChat(Text.translatable("firmament.poweruser.entity.name", target.name)) + if (target is LivingEntity) { + MC.sendChat(Text.translatable("firmament.poweruser.entity.armor")) + for (armorItem in target.armorItems) { + MC.sendChat(Text.translatable("firmament.poweruser.entity.armor.item", debugFormat(armorItem))) + } + } + MC.sendChat(Text.stringifiedTranslatable("firmament.poweruser.entity.passengers", target.passengerList.size)) + target.passengerList.forEach { + showEntity(target) + } + } + + @Subscribe fun copyInventoryInfo(it: HandledScreenKeyPressedEvent) { if (it.screen !is AccessorHandledScreen) return diff --git a/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt b/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt new file mode 100644 index 0000000..5735e76 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/events/anniversity/AnniversaryFeatures.kt @@ -0,0 +1,229 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.features.events.anniversity + +import io.github.notenoughupdates.moulconfig.observer.ObservableList +import io.github.notenoughupdates.moulconfig.xml.Bind +import moe.nea.jarvis.api.Point +import kotlin.time.Duration.Companion.seconds +import net.minecraft.entity.passive.PigEntity +import net.minecraft.util.math.BlockPos +import moe.nea.firmament.annotations.Subscribe +import moe.nea.firmament.events.EntityInteractionEvent +import moe.nea.firmament.events.ProcessChatEvent +import moe.nea.firmament.events.TickEvent +import moe.nea.firmament.events.WorldReadyEvent +import moe.nea.firmament.features.FirmamentFeature +import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.gui.hud.MoulConfigHud +import moe.nea.firmament.rei.SBItemEntryDefinition +import moe.nea.firmament.repo.ItemNameLookup +import moe.nea.firmament.util.MC +import moe.nea.firmament.util.SHORT_NUMBER_FORMAT +import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.TimeMark +import moe.nea.firmament.util.parseShortNumber +import moe.nea.firmament.util.useMatch + +object AnniversaryFeatures : FirmamentFeature { + override val identifier: String + get() = "anniversary" + + object TConfig : ManagedConfig(identifier) { + val enableShinyPigTracker by toggle("shiny-pigs") {true} + val trackPigCooldown by position("pig-hud", 200, 300) { Point(0.1, 0.2) } + } + + override val config: ManagedConfig? + get() = TConfig + + data class ClickedPig( + val clickedAt: TimeMark, + val startLocation: BlockPos, + val pigEntity: PigEntity + ) { + @Bind("timeLeft") + fun getTimeLeft(): Double = 1 - clickedAt.passedTime() / pigDuration + } + + val clickedPigs = ObservableList<ClickedPig>(mutableListOf()) + var lastClickedPig: PigEntity? = null + + val pigDuration = 90.seconds + + @Subscribe + fun onTick(event: TickEvent) { + clickedPigs.removeIf { it.clickedAt.passedTime() > pigDuration } + } + + val pattern = "SHINY! You extracted (?<reward>.*) from the piglet's orb!".toPattern() + + @Subscribe + fun onChat(event: ProcessChatEvent) { + if(!TConfig.enableShinyPigTracker)return + if (event.unformattedString == "Oink! Bring the pig back to the Shiny Orb!") { + val pig = lastClickedPig ?: return + // TODO: store proper location based on the orb location, maybe + val startLocation = pig.blockPos ?: return + clickedPigs.add(ClickedPig(TimeMark.now(), startLocation, pig)) + lastClickedPig = null + } + if (event.unformattedString == "SHINY! The orb is charged! Click on it for loot!") { + val player = MC.player ?: return + val lowest = + clickedPigs.minByOrNull { it.startLocation.getSquaredDistance(player.pos) } ?: return + clickedPigs.remove(lowest) + } + pattern.useMatch(event.unformattedString) { + val reward = group("reward") + val parsedReward = parseReward(reward) + addReward(parsedReward) + PigCooldown.rewards.atOnce { + PigCooldown.rewards.clear() + rewards.mapTo(PigCooldown.rewards) { PigCooldown.DisplayReward(it) } + } + } + } + + fun addReward(reward: Reward) { + val it = rewards.listIterator() + while (it.hasNext()) { + val merged = reward.mergeWith(it.next()) ?: continue + it.set(merged) + return + } + rewards.add(reward) + } + + val rewards = mutableListOf<Reward>() + + fun <T> ObservableList<T>.atOnce(block: () -> Unit) { + val oldObserver = observer + observer = null + block() + observer = oldObserver + update() + } + + sealed interface Reward { + fun mergeWith(other: Reward): Reward? + data class EXP(val amount: Double, val skill: String) : Reward { + override fun mergeWith(other: Reward): Reward? { + if (other is EXP && other.skill == skill) + return EXP(amount + other.amount, skill) + return null + } + } + + data class Coins(val amount: Double) : Reward { + override fun mergeWith(other: Reward): Reward? { + if (other is Coins) + return Coins(other.amount + amount) + return null + } + } + + data class Items(val amount: Int, val item: SkyblockId) : Reward { + override fun mergeWith(other: Reward): Reward? { + if (other is Items && other.item == item) + return Items(amount + other.amount, item) + return null + } + } + + data class Unknown(val text: String) : Reward { + override fun mergeWith(other: Reward): Reward? { + return null + } + } + } + + val expReward = "\\+(?<exp>$SHORT_NUMBER_FORMAT) (?<kind>[^ ]+) XP".toPattern() + val coinReward = "\\+(?<amount>$SHORT_NUMBER_FORMAT) coins".toPattern() + val itemReward = "(?:(?<amount>[0-9]+)x )?(?<name>.*)".toPattern() + fun parseReward(string: String): Reward { + expReward.useMatch<Unit>(string) { + val exp = parseShortNumber(group("exp")) + val kind = group("kind") + return Reward.EXP(exp, kind) + } + coinReward.useMatch<Unit>(string) { + val coins = parseShortNumber(group("amount")) + return Reward.Coins(coins) + } + itemReward.useMatch(string) { + val amount = group("amount")?.toIntOrNull() ?: 1 + val name = group("name") + val item = ItemNameLookup.guessItemByName(name, false) ?: return@useMatch + return Reward.Items(amount, item) + } + return Reward.Unknown(string) + } + + @Subscribe + fun onWorldClear(event: WorldReadyEvent) { + lastClickedPig = null + clickedPigs.clear() + } + + @Subscribe + fun onEntityClick(event: EntityInteractionEvent) { + if (event.entity is PigEntity) { + lastClickedPig = event.entity + } + } + + @Subscribe + fun init(event: WorldReadyEvent) { + PigCooldown.forceInit() + } + + object PigCooldown : MoulConfigHud("anniversary_pig", TConfig.trackPigCooldown) { + override fun shouldRender(): Boolean { + return clickedPigs.isNotEmpty() && TConfig.enableShinyPigTracker + } + + @Bind("pigs") + fun getPigs() = clickedPigs + + class DisplayReward(val backedBy: Reward) { + @Bind + fun count(): String { + return when (backedBy) { + is Reward.Coins -> backedBy.amount + is Reward.EXP -> backedBy.amount + is Reward.Items -> backedBy.amount + is Reward.Unknown -> 0 + }.toString() + } + + val itemStack = if (backedBy is Reward.Items) { + SBItemEntryDefinition.getEntry(backedBy.item, backedBy.amount) + } else { + SBItemEntryDefinition.getEntry(SkyblockId.NULL) + } + + @Bind + fun name(): String { + return when (backedBy) { + is Reward.Coins -> "Coins" + is Reward.EXP -> backedBy.skill + is Reward.Items -> itemStack.value.asItemStack().name.string + is Reward.Unknown -> backedBy.text + } + } + + @Bind + fun isKnown() = backedBy !is Reward.Unknown + } + + @get:Bind("rewards") + val rewards = ObservableList<DisplayReward>(mutableListOf()) + + } + +} |