diff options
author | Helfull <admin@helfull.de> | 2023-10-17 12:30:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-17 12:30:23 +0200 |
commit | 48a41d5dd03a7fa591827f3bcb0f9d6f2dc27e9a (patch) | |
tree | 5374eb81ed19d929187eb98a0a88433329e32b88 | |
parent | 8116fb8434a724b67be01e1369ef902b865d5c49 (diff) | |
download | skyhanni-48a41d5dd03a7fa591827f3bcb0f9d6f2dc27e9a.tar.gz skyhanni-48a41d5dd03a7fa591827f3bcb0f9d6f2dc27e9a.tar.bz2 skyhanni-48a41d5dd03a7fa591827f3bcb0f9d6f2dc27e9a.zip |
Internal Changes: Refactor VisitorAPI to event based interaction (#561)
Split up GardenVisitorFeatures into multiple useful events #561
21 files changed, 706 insertions, 329 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index d4a851e13..d1efb4eb0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -94,6 +94,7 @@ dependencies { // testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") + testImplementation("io.mockk:mockk:1.12.5") } tasks.withType(Test::class) { diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index ce7ad3490..cd2c458c8 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -142,6 +142,7 @@ import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorColorNames import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorTimer +import at.hannibal2.skyhanni.features.garden.visitor.VisitorListener import at.hannibal2.skyhanni.features.inventory.AuctionsHighlighter import at.hannibal2.skyhanni.features.inventory.HideNotClickableItems import at.hannibal2.skyhanni.features.inventory.HighlightBonzoMasks @@ -345,6 +346,7 @@ class SkyHanniMod { loadModule(RenderData()) loadModule(GardenCropMilestones) loadModule(GardenCropUpgrades()) + loadModule(VisitorListener()) loadModule(OwnInventoryData()) loadModule(ToolTipData()) loadModule(GuiEditManager()) diff --git a/src/main/java/at/hannibal2/skyhanni/events/VisitorAcceptEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/VisitorAcceptEvent.kt index 620694a22..af6fa275a 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/VisitorAcceptEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/VisitorAcceptEvent.kt @@ -1,5 +1,5 @@ package at.hannibal2.skyhanni.events -import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI -class VisitorAcceptEvent(val visitor: GardenVisitorFeatures.Visitor) : LorenzEvent()
\ No newline at end of file +class VisitorAcceptEvent(val visitor: VisitorAPI.Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/VisitorArrivalEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/VisitorArrivalEvent.kt deleted file mode 100644 index 91be1bbe5..000000000 --- a/src/main/java/at/hannibal2/skyhanni/events/VisitorArrivalEvent.kt +++ /dev/null @@ -1,5 +0,0 @@ -package at.hannibal2.skyhanni.events - -import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures.Visitor - -class VisitorArrivalEvent(val visitor: Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorAcceptedEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorAcceptedEvent.kt new file mode 100644 index 000000000..e3bffed8b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorAcceptedEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI + +class VisitorAcceptedEvent(val visitor: VisitorAPI.Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorArrivalEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorArrivalEvent.kt new file mode 100644 index 000000000..673f45e20 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorArrivalEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.Visitor + +class VisitorArrivalEvent(val visitor: Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorLeftEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorLeftEvent.kt new file mode 100644 index 000000000..f906364ce --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorLeftEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI + +class VisitorLeftEvent(val visitor: VisitorAPI.Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorOpenEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorOpenEvent.kt new file mode 100644 index 000000000..6abec9865 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorOpenEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI + +class VisitorOpenEvent(val visitor: VisitorAPI.Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRefusedEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRefusedEvent.kt new file mode 100644 index 000000000..fea24fba9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRefusedEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI + +class VisitorRefusedEvent(val visitor: VisitorAPI.Visitor) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRenderEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRenderEvent.kt new file mode 100644 index 000000000..f050d53a5 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorRenderEvent.kt @@ -0,0 +1,9 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI +import at.hannibal2.skyhanni.utils.LorenzVec +import net.minecraftforge.client.event.RenderWorldLastEvent + +class VisitorRenderEvent(val visitor: VisitorAPI.Visitor, val location: LorenzVec, val parent: LorenzRenderWorldEvent) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorToolTipEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorToolTipEvent.kt new file mode 100644 index 000000000..daf1439f3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/garden/visitor/VisitorToolTipEvent.kt @@ -0,0 +1,7 @@ +package at.hannibal2.skyhanni.events.garden.visitor + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI +import net.minecraft.item.ItemStack + +class VisitorToolTipEvent(val visitor: VisitorAPI.Visitor, val itemStack: ItemStack, val toolTip: MutableList<String>) : LorenzEvent()
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt index b0d0013a1..fd98cd437 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/AnitaMedalProfit.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getLore @@ -47,7 +48,7 @@ class AnitaMedalProfit { fun onInventoryOpen(event: InventoryFullyOpenedEvent) { if (!config.medalProfitEnabled) return if (event.inventoryName != "Anita") return - if (GardenVisitorFeatures.inVisitorInventory) return + if (VisitorAPI.inVisitorInventory) return inInventory = true diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt index 8c7ceba3a..378b72e35 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt @@ -3,27 +3,24 @@ package at.hannibal2.skyhanni.features.garden.visitor import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.events.CheckRenderEntityEvent import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.OwnInventoryItemUpdateEvent -import at.hannibal2.skyhanni.events.PacketEvent import at.hannibal2.skyhanni.events.PreProfileSwitchEvent import at.hannibal2.skyhanni.events.TabListLineRenderEvent -import at.hannibal2.skyhanni.events.TabListUpdateEvent import at.hannibal2.skyhanni.events.VisitorAcceptEvent -import at.hannibal2.skyhanni.events.VisitorArrivalEvent -import at.hannibal2.skyhanni.events.withAlpha +import at.hannibal2.skyhanni.events.garden.visitor.VisitorAcceptedEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorArrivalEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorOpenEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorRefusedEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorRenderEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorToolTipEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi import at.hannibal2.skyhanni.features.garden.CropType.Companion.getByNameOrNull import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper -import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.EntityUtils import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemBlink @@ -33,13 +30,9 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getItemName import at.hannibal2.skyhanni.utils.ItemUtils.getItemNameOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld -import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer -import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzLogger import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addAsSingletonList -import at.hannibal2.skyhanni.utils.LorenzUtils.editCopy import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getItemStack @@ -47,37 +40,29 @@ import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RenderUtils.drawString -import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TimeUtils import at.hannibal2.skyhanni.utils.getLorenzVec import at.hannibal2.skyhanni.utils.renderables.Renderable -import io.github.moulberry.notenoughupdates.events.SlotClickEvent import io.github.moulberry.notenoughupdates.util.MinecraftExecutor import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiEditSign -import net.minecraft.entity.Entity import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.item.EntityArmorStand import net.minecraft.item.ItemStack -import net.minecraft.network.play.client.C02PacketUseEntity import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent import net.minecraftforge.client.event.RenderLivingEvent -import net.minecraftforge.event.entity.player.ItemTooltipEvent import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import org.lwjgl.input.Keyboard import kotlin.math.round import kotlin.time.Duration.Companion.seconds -private val config get() = SkyHanniMod.feature.garden.visitors +private val config get() = VisitorAPI.config class GardenVisitorFeatures { - private var visitors = mapOf<String, Visitor>() private var display = emptyList<List<Any>>() - private var lastClickedNpc = 0 private val newVisitorArrivedMessage = ".* §r§ehas arrived on your §r§bGarden§r§e!".toPattern() private val copperPattern = " §8\\+§c(?<amount>.*) Copper".toPattern() private val gardenExperiencePattern = " §8\\+§2(?<amount>.*) §7Garden Experience".toPattern() @@ -86,45 +71,16 @@ class GardenVisitorFeatures { private val logger = LorenzLogger("garden/visitors") private var lastFullPrice = 0.0 - companion object { - var inVisitorInventory = false - } - @SubscribeEvent fun onPreProfileSwitch(event: PreProfileSwitchEvent) { display = emptyList() - visitors = emptyMap() } @SubscribeEvent - fun onInventoryOpen(event: InventoryFullyOpenedEvent) { - if (!GardenAPI.inGarden()) return - val npcItem = event.inventoryItems[13] ?: return - val lore = npcItem.getLore() - var isVisitor = false - if (lore.size == 4) { - val line = lore[3] - if (line.startsWith("§7Offers Accepted: §a")) { - isVisitor = true - } - } - if (!isVisitor) return - - val offerItem = event.inventoryItems[29] ?: return - if (offerItem.name != "§aAccept Offer") return - - inVisitorInventory = true - - if (!config.needs.display && config.highlightStatus == 3) return - - var name = npcItem.name ?: return - if (name.length == name.removeColor().length + 4) { - name = name.substring(2) - } - - val visitor = getOrCreateVisitor(name) ?: return + fun onVisitorOpen(event: VisitorOpenEvent) { + val visitor = event.visitor + val offerItem = visitor.offer!!.offerItem - visitor.entityId = lastClickedNpc for (line in offerItem.getLore()) { if (line == "§7Items Required:") continue if (line.isEmpty()) break @@ -138,54 +94,22 @@ class GardenVisitorFeatures { val internalName = NEUInternalName.fromItemName(itemName) visitor.items[internalName] = amount } - readToolTip(visitor, event.inventoryItems[29]) - if (visitor.status == VisitorStatus.NEW) { - val alreadyReady = event.inventoryItems[29]?.getLore()?.any { it == "§eClick to give!" } == true + readToolTip(visitor, offerItem) + + if (visitor.status == VisitorAPI.VisitorStatus.NEW) { + val alreadyReady = offerItem.getLore().any { it == "§eClick to give!" } == true if (alreadyReady) { - changeStatus(visitor, VisitorStatus.READY, "inSacks") + VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.READY, "inSacks") visitor.inSacks = true update() } else { - val waiting = VisitorStatus.WAITING - changeStatus(visitor, waiting, "firstContact") + VisitorAPI.changeStatus(visitor, VisitorAPI.VisitorStatus.WAITING, "firstContact") } update() } } - private fun getOrCreateVisitor(name: String): Visitor? { - var visitor = visitors[name] - if (visitor == null) { - // workaround if the tab list has not yet updated when opening the visitor - addVisitor(name) - LorenzUtils.debug("Found visitor from npc that is not in tab list. Adding it still.") - updateDisplay() - visitor = visitors[name] - } - - if (visitor != null) return visitor - - println("visitors: $visitors") - println("name: $name") - ErrorManager.logErrorState( - "Error finding the visitor `$name§c`. Try to reopen the inventory", - "visitor is null! name='$name', visitors=`$visitors`" - ) - return null - } - - private fun readReward(offerItem: ItemStack): VisitorReward? { - for (line in offerItem.getLore()) { - for (reward in VisitorReward.entries) { - if (line.contains(reward.displayName)) { - return reward - } - } - } - return null - } - private fun updateDisplay() { display = drawDisplay() } @@ -196,8 +120,8 @@ class GardenVisitorFeatures { val requiredItems = mutableMapOf<NEUInternalName, Int>() val newVisitors = mutableListOf<String>() - for ((visitorName, visitor) in visitors) { - if (visitor.status == VisitorStatus.ACCEPTED || visitor.status == VisitorStatus.REFUSED) continue + for ((visitorName, visitor) in VisitorAPI.getVisitorsMap()) { + if (visitor.status == VisitorAPI.VisitorStatus.ACCEPTED || visitor.status == VisitorAPI.VisitorStatus.REFUSED) continue val items = visitor.items if (items.isEmpty()) { @@ -294,102 +218,42 @@ class GardenVisitorFeatures { } } - @SubscribeEvent(priority = EventPriority.HIGH) - fun onStackClick(event: SlotClickEvent) { - if (!inVisitorInventory) return - if (event.clickType != 0) return - - val visitor = getVisitor(lastClickedNpc) ?: return - - if (event.slotId == 33) { - if (event.slot.stack?.name != "§cRefuse Offer") return - - visitor.hasReward()?.let { - if (config.rewardWarning.preventRefusing) { - if (config.rewardWarning.bypassKey.isKeyHeld()) { - LorenzUtils.chat("§e[SkyHanni] §cBypassed blocking refusal of visitor ${visitor.visitorName} §7(${it.displayName}§7)") - return - } - event.isCanceled = true - LorenzUtils.chat("§e[SkyHanni] §cBlocked refusing visitor ${visitor.visitorName} §7(${it.displayName}§7)") - if (config.rewardWarning.bypassKey == Keyboard.KEY_NONE) { - LorenzUtils.clickableChat( - "§eIf you want to deny this visitor, set a keybind in §e/sh bypass", - "sh bypass" - ) - } - Minecraft.getMinecraft().thePlayer.closeScreen() - return - } - } - - changeStatus(visitor, VisitorStatus.REFUSED, "refused") - update() - GardenVisitorDropStatistics.deniedVisitors += 1 - GardenVisitorDropStatistics.saveAndUpdate() - return - } - if (event.slotId == 29 && event.slot.stack?.getLore()?.any { it == "§eClick to give!" } == true) { - changeStatus(visitor, VisitorStatus.ACCEPTED, "accepted") - acceptVisitor(visitor) - update() - GardenVisitorDropStatistics.coinsSpent += round(lastFullPrice).toLong() - GardenVisitorDropStatistics.lastAccept = System.currentTimeMillis() - return - } - } - - private fun acceptVisitor(visitor: Visitor) { - VisitorAcceptEvent(visitor).postAndCatch() + @SubscribeEvent + fun onVisitorRefused(event: VisitorRefusedEvent) { + update() + GardenVisitorDropStatistics.deniedVisitors += 1 + GardenVisitorDropStatistics.saveAndUpdate() } - private fun getVisitor(id: Int) = visitors.map { it.value }.find { it.entityId == id } - @SubscribeEvent - fun onCheckRender(event: CheckRenderEntityEvent<*>) { - if (!GardenAPI.inGarden()) return - if (!GardenAPI.onBarnPlot) return - if (config.highlightStatus != 1 && config.highlightStatus != 2) return - - val entity = event.entity - if (entity is EntityArmorStand && entity.name == "§e§lCLICK") { - event.isCanceled = true - } + fun onVisitorAccepted(event: VisitorAcceptedEvent) { + VisitorAcceptEvent(event.visitor).postAndCatch() + update() + GardenVisitorDropStatistics.coinsSpent += round(lastFullPrice).toLong() + GardenVisitorDropStatistics.lastAccept = System.currentTimeMillis() } @SubscribeEvent - fun onRenderWorld(event: LorenzRenderWorldEvent) { - if (!GardenAPI.inGarden()) return - if (!GardenAPI.onBarnPlot) return - if (config.highlightStatus != 1 && config.highlightStatus != 2) return - - for (visitor in visitors.values) { - visitor.getNameTagEntity()?.let { - val location = event.exactLocation(it) - if (it.distanceToPlayer() < 15) { - val text = visitor.status.displayName - event.drawString(location.add(0.0, 2.23, 0.0), text) - if (config.rewardWarning.showOverName) { - visitor.hasReward()?.let { reward -> - val name = reward.displayName - - event.drawString(location.add(0.0, 2.73, 0.0), "§c!$name§c!") - } - } - } + fun onVisitorRender(event: VisitorRenderEvent) { + val visitor = event.visitor + val text = visitor.status.displayName + val location = event.location + event.parent.drawString(location.add(0.0, 2.23, 0.0), text) + if (config.rewardWarning.showOverName) { + visitor.hasReward()?.let { reward -> + val name = reward.displayName + + event.parent.drawString(location.add(0.0, 2.73, 0.0), "§c!$name§c!") } } } @SubscribeEvent(priority = EventPriority.HIGH) - fun onTooltip(event: ItemTooltipEvent) { - if (!GardenAPI.onBarnPlot) return - if (!inVisitorInventory) return + fun onVisitorTooltip(event: VisitorToolTipEvent) { if (event.itemStack.name != "§aAccept Offer") return - val visitor = getVisitor(lastClickedNpc) ?: return - - val toolTip = event.toolTip ?: return + val visitor = event.visitor + val toolTip = event.toolTip toolTip.clear() if (visitor.lastLore.isEmpty()) { @@ -400,7 +264,7 @@ class GardenVisitorFeatures { toolTip.addAll(visitor.lastLore) } - private fun readToolTip(visitor: Visitor, itemStack: ItemStack?) { + private fun readToolTip(visitor: VisitorAPI.Visitor, itemStack: ItemStack?) { val stack = itemStack ?: error("Accept offer item not found for visitor ${visitor.visitorName}") var totalPrice = 0.0 var timeRequired = -1L @@ -512,74 +376,11 @@ class GardenVisitorFeatures { } @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - inVisitorInventory = false - } - - @SubscribeEvent - fun onTabListUpdate(event: TabListUpdateEvent) { - if (!GardenAPI.inGarden()) return - var found = false - val visitorsInTab = mutableListOf<String>() - for (line in event.tabList) { - if (line.startsWith("§b§lVisitors:")) { - found = true - continue - } - if (found) { - if (line.isEmpty()) { - found = false - continue - } - val name = fromHypixelName(line) - - // Hide hypixel watchdog entries - if (name.contains("§c") && !name.contains("Spaceman") && !name.contains("Grandma Wolf")) { - logger.log("Ignore wrong red name: '$name'") - continue - } - - //hide own player name - if (name.contains(LorenzUtils.getPlayerName())) { - logger.log("Ignore wrong own name: '$name'") - continue - } - - visitorsInTab.add(name) - } - } - val removedVisitors = mutableListOf<String>() - visitors.forEach { - val name = it.key - val time = System.currentTimeMillis() - LorenzUtils.lastWorldSwitch - val removed = name !in visitorsInTab && time > 2_000 - if (removed) { - logger.log("Removed old visitor: '$name'") - removedVisitors.add(name) - } - } - var dirty = false - if (removedVisitors.isNotEmpty()) { - visitors = visitors.editCopy { - keys.removeIf { it in removedVisitors } - } - dirty = true - } - for (name in visitorsInTab) { - if (!visitors.containsKey(name)) { - addVisitor(name) - dirty = true - } - } - if (dirty) { - updateDisplay() - } - } + fun onVisitorArrival(event: VisitorArrivalEvent) { + val visitor = event.visitor + val name = visitor.visitorName - private fun addVisitor(name: String) { - val visitor = Visitor(name, status = VisitorStatus.NEW) - visitors = visitors.editCopy { this[name] = visitor } - VisitorArrivalEvent(visitor).postAndCatch() + update() logger.log("New visitor detected: '$name'") @@ -603,21 +404,13 @@ class GardenVisitorFeatures { } } - private fun fromHypixelName(line: String): String { - var name = line.trim().replace("§r", "").trim() - if (!name.contains("§")) { - name = "§f$name" - } - return name - } - @SubscribeEvent fun onTabListText(event: TabListLineRenderEvent) { if (!GardenAPI.inGarden()) return if (!config.coloredName) return val text = event.text - val replace = fromHypixelName(text) - val visitor = visitors[replace] + val replace = VisitorAPI.fromHypixelName(text) + val visitor = VisitorAPI.getVisitor(replace) visitor?.let { event.text = " " + GardenVisitorColorNames.getColoredName(it.visitorName) } @@ -639,7 +432,7 @@ class GardenVisitorFeatures { if (name == "Spaceman") return false if (name == "Beth") return false - return visitors.keys.any { it.removeColor() == name } + return VisitorAPI.getVisitorsMap().keys.any { it.removeColor() == name } } ?: false private fun update() { @@ -648,7 +441,8 @@ class GardenVisitorFeatures { } private fun checkVisitorsReady() { - for ((visitorName, visitor) in visitors) { + for (visitor in VisitorAPI.getVisitors()) { + val visitorName = visitor.visitorName val entity = visitor.getEntity() if (entity == null) { findNametag(visitorName.removeColor())?.let { @@ -658,9 +452,9 @@ class GardenVisitorFeatures { if (!visitor.inSacks) { val status = visitor.status - if (status == VisitorStatus.WAITING || status == VisitorStatus.READY) { - val newStatus = if (hasItemsInInventory(visitor)) VisitorStatus.READY else VisitorStatus.WAITING - changeStatus(visitor, newStatus, "hasItemsInInventory") + if (status == VisitorAPI.VisitorStatus.WAITING || status == VisitorAPI.VisitorStatus.READY) { + val newStatus = if (hasItemsInInventory(visitor)) VisitorAPI.VisitorStatus.READY else VisitorAPI.VisitorStatus.WAITING + VisitorAPI.changeStatus(visitor, newStatus, "hasItemsInInventory") } } @@ -678,14 +472,7 @@ class GardenVisitorFeatures { } } - private fun changeStatus(visitor: Visitor, newStatus: VisitorStatus, reason: String) { - val old = visitor.status - if (old == newStatus) return - visitor.status = newStatus - logger.log("Visitor status change for '${visitor.visitorName}': $old -> $newStatus ($reason)") - } - - private fun findEntity(nameTag: EntityArmorStand, visitor: Visitor) { + private fun findEntity(nameTag: EntityArmorStand, visitor: VisitorAPI.Visitor) { for (entity in EntityUtils.getAllEntities()) { if (entity is EntityArmorStand) continue if (entity.getLorenzVec().distanceIgnoreY(nameTag.getLorenzVec()) != 0.0) continue @@ -722,7 +509,7 @@ class GardenVisitorFeatures { return foundVisitorNameTags[0] } - private fun hasItemsInInventory(visitor: Visitor): Boolean { + private fun hasItemsInInventory(visitor: VisitorAPI.Visitor): Boolean { var ready = true for ((internalName, need) in visitor.items) { val having = InventoryUtils.countItemsInLowerInventory { it.getInternalName() == internalName } @@ -733,19 +520,6 @@ class GardenVisitorFeatures { return ready } - // TODO make event - @SubscribeEvent - fun onSendEvent(event: PacketEvent.SendEvent) { - val packet = event.packet - if (packet !is C02PacketUseEntity) return - - val theWorld = Minecraft.getMinecraft().theWorld - val entity = packet.getEntityFromWorld(theWorld) ?: return - val entityId = entity.entityId - - lastClickedNpc = entityId - } - @SubscribeEvent fun onRenderInSigns(event: DrawScreenEvent.Post) { if (!GardenAPI.inGarden()) return @@ -787,49 +561,13 @@ class GardenVisitorFeatures { if (!config.coloredName) return val entity = event.entity val entityId = entity.entityId - for (visitor in visitors.values) { + for (visitor in VisitorAPI.getVisitors()) { if (visitor.nameTagEntityId == entityId) { entity.customNameTag = GardenVisitorColorNames.getColoredName(entity.name) } } } - class Visitor( - val visitorName: String, - var entityId: Int = -1, - var nameTagEntityId: Int = -1, - var status: VisitorStatus, - var inSacks: Boolean = false, - val items: MutableMap<NEUInternalName, Int> = mutableMapOf(), - ) { - - var allRewards = listOf<NEUInternalName>() - var lastLore = listOf<String>() - fun getEntity(): Entity? = Minecraft.getMinecraft().theWorld.getEntityByID(entityId) - - fun getNameTagEntity(): Entity? = Minecraft.getMinecraft().theWorld.getEntityByID(nameTagEntityId) - - fun hasReward(): VisitorReward? { - for (internalName in allRewards) { - val reward = VisitorReward.getByInternalName(internalName) ?: continue - - if (config.rewardWarning.drops.contains(reward.ordinal)) { - return reward - } - } - - return null - } - } - - enum class VisitorStatus(val displayName: String, val color: Int) { - NEW("§eNew", LorenzColor.YELLOW.toColor().withAlpha(100)), - WAITING("Waiting", -1), - READY("§aItems Ready", LorenzColor.GREEN.toColor().withAlpha(80)), - ACCEPTED("§7Accepted", LorenzColor.DARK_GRAY.toColor().withAlpha(80)), - REFUSED("§cRefused", LorenzColor.RED.toColor().withAlpha(60)), - } - @SubscribeEvent fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { event.move(3, "garden.visitorNeedsDisplay", "garden.visitors.needs.display") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt index dedd034fa..a4b86e03c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorTimer.kt @@ -6,7 +6,7 @@ import at.hannibal2.skyhanni.events.CropClickEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.PreProfileSwitchEvent -import at.hannibal2.skyhanni.events.VisitorArrivalEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorArrivalEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.LorenzUtils diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt new file mode 100644 index 000000000..4f9bbb23d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorAPI.kt @@ -0,0 +1,140 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.garden.visitor.VisitorAcceptedEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorArrivalEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorLeftEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorRefusedEvent +import at.hannibal2.skyhanni.events.withAlpha +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzLogger +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.editCopy +import at.hannibal2.skyhanni.utils.NEUInternalName +import net.minecraft.client.Minecraft +import net.minecraft.entity.Entity +import net.minecraft.item.ItemStack + +object VisitorAPI { + private var visitors = mapOf<String, Visitor>() + var inVisitorInventory = false + val config get() = SkyHanniMod.feature.garden.visitors + private val logger = LorenzLogger("garden/visitors/api") + + fun getVisitorsMap() = visitors + fun getVisitors() = visitors.values + fun getVisitor(id: Int) = visitors.map { it.value }.find { it.entityId == id } + fun getVisitor(name: String) = visitors[name] + + fun reset() { + visitors = emptyMap() + } + + fun changeStatus(visitor: Visitor, newStatus: VisitorStatus, reason: String) { + val old = visitor.status + if (old == newStatus) return + visitor.status = newStatus + logger.log("Visitor status change for '${visitor.visitorName}': $old -> $newStatus ($reason)") + + when (newStatus) { + VisitorStatus.ACCEPTED -> { + VisitorAcceptedEvent(visitor).postAndCatch() + } + VisitorStatus.REFUSED -> { + VisitorRefusedEvent(visitor).postAndCatch() + } + else -> {} + } + } + + fun getOrCreateVisitor(name: String): Visitor? { + var visitor = visitors[name] + if (visitor == null) { + // workaround if the tab list has not yet updated when opening the visitor + addVisitor(name) + LorenzUtils.debug("Found visitor from npc that is not in tab list. Adding it still.") + visitor = visitors[name] + } + + if (visitor != null) return visitor + + println("visitors: $visitors") + println("name: $name") + ErrorManager.logErrorState( + "Error finding the visitor `$name§c`. Try to reopen the inventory", + "visitor is null! name='$name', visitors=`$visitors`" + ) + return null + } + + fun removeVisitor(name: String): Boolean { + if (!visitors.containsKey(name)) return false + val visitor = visitors[name] ?: return false + visitors = visitors.editCopy { remove(name) } + VisitorLeftEvent(visitor).postAndCatch() + return true + } + + fun addVisitor(name: String): Boolean { + if (visitors.containsKey(name)) return false + val visitor = Visitor(name, status = VisitorStatus.NEW) + visitors = visitors.editCopy { this[name] = visitor } + VisitorArrivalEvent(visitor).postAndCatch() + return true + } + + fun fromHypixelName(line: String): String { + var name = line.trim().replace("§r", "").trim() + if (!name.contains("§")) { + name = "§f$name" + } + return name + } + + fun isVisitorInfo(lore: List<String>): Boolean { + if (lore.size != 4) return false + return lore[3].startsWith("§7Offers Accepted: §a") + } + + class VisitorOffer( + val offerItem: ItemStack + ) + + class Visitor( + val visitorName: String, + var entityId: Int = -1, + var nameTagEntityId: Int = -1, + var status: VisitorStatus, + var inSacks: Boolean = false, + val items: MutableMap<NEUInternalName, Int> = mutableMapOf(), + var offer: VisitorOffer? = null, + ) { + var lore: List<String> = emptyList() + var allRewards = listOf<NEUInternalName>() + var lastLore = listOf<String>() + + fun getEntity(): Entity? = Minecraft.getMinecraft().theWorld.getEntityByID(entityId) + fun getNameTagEntity(): Entity? = Minecraft.getMinecraft().theWorld.getEntityByID(nameTagEntityId) + + fun hasReward(): VisitorReward? { + for (internalName in allRewards) { + val reward = VisitorReward.getByInternalName(internalName) ?: continue + + if (config.rewardWarning.drops.contains(reward.ordinal)) { + return reward + } + } + + return null + } + } + + enum class VisitorStatus(val displayName: String, val color: Int) { + NEW("§eNew", LorenzColor.YELLOW.toColor().withAlpha(100)), + WAITING("Waiting", -1), + READY("§aItems Ready", LorenzColor.GREEN.toColor().withAlpha(80)), + ACCEPTED("§7Accepted", LorenzColor.DARK_GRAY.toColor().withAlpha(80)), + REFUSED("§cRefused", LorenzColor.RED.toColor().withAlpha(60)), + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt new file mode 100644 index 000000000..c03d666f9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt @@ -0,0 +1,212 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.events.CheckRenderEntityEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent +import at.hannibal2.skyhanni.events.PacketEvent +import at.hannibal2.skyhanni.events.PreProfileSwitchEvent +import at.hannibal2.skyhanni.events.TabListUpdateEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorOpenEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorRenderEvent +import at.hannibal2.skyhanni.events.garden.visitor.VisitorToolTipEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI.VisitorStatus +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer +import at.hannibal2.skyhanni.utils.LorenzLogger +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RenderUtils.exactLocation +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import io.github.moulberry.notenoughupdates.events.SlotClickEvent +import net.minecraft.client.Minecraft +import net.minecraft.entity.item.EntityArmorStand +import net.minecraft.network.play.client.C02PacketUseEntity +import net.minecraftforge.event.entity.player.ItemTooltipEvent +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.lwjgl.input.Keyboard + +private val config get() = VisitorAPI.config + +class VisitorListener { + private var lastClickedNpc = 0 + private val logger = LorenzLogger("garden/visitors/listener") + + companion object { + private val VISITOR_INFO_ITEM_SLOT = 13 + private val VISITOR_ACCEPT_ITEM_SLOT = 29 + private val VISITOR_REFUSE_ITEM_SLOT = 33 + } + + @SubscribeEvent + fun onPreProfileSwitch(event: PreProfileSwitchEvent) { + VisitorAPI.reset() + } + + // TODO make event + @SubscribeEvent + fun onSendEvent(event: PacketEvent.SendEvent) { + val packet = event.packet + if (packet !is C02PacketUseEntity) return + + val theWorld = Minecraft.getMinecraft().theWorld + val entity = packet.getEntityFromWorld(theWorld) ?: return + val entityId = entity.entityId + + lastClickedNpc = entityId + } + + @SubscribeEvent + fun onTabListUpdate(event: TabListUpdateEvent) { + if (!GardenAPI.inGarden()) return + var found = false + val visitorsInTab = mutableListOf<String>() + for (line in event.tabList) { + if (line.startsWith("§b§lVisitors:")) { + found = true + continue + } + if (!found) continue + + if (line.isEmpty()) { + found = false + continue + } + val name = VisitorAPI.fromHypixelName(line) + + // Hide hypixel watchdog entries + if (name.contains("§c") && !name.contains("Spaceman") && !name.contains("Grandma Wolf")) { + logger.log("Ignore wrong red name: '$name'") + continue + } + + //hide own player name + if (name.contains(LorenzUtils.getPlayerName())) { + logger.log("Ignore wrong own name: '$name'") + continue + } + + visitorsInTab.add(name) + } + + VisitorAPI.getVisitors().forEach { + val name = it.visitorName + val time = System.currentTimeMillis() - LorenzUtils.lastWorldSwitch + val removed = name !in visitorsInTab && time > 2_000 + if (removed) { + logger.log("Removed old visitor: '$name'") + VisitorAPI.removeVisitor(name) + } + } + + for (name in visitorsInTab) { + VisitorAPI.addVisitor(name) + } + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryFullyOpenedEvent) { + if (!GardenAPI.inGarden()) return + val npcItem = event.inventoryItems[VISITOR_INFO_ITEM_SLOT] ?: return + val lore = npcItem.getLore() + if(!VisitorAPI.isVisitorInfo(lore)) return + + val offerItem = event.inventoryItems[VISITOR_ACCEPT_ITEM_SLOT] ?: return + if (offerItem.name != "§aAccept Offer") return + + VisitorAPI.inVisitorInventory = true + + val visitorOffer = VisitorAPI.VisitorOffer(offerItem) + + var name = npcItem.name ?: return + if (name.length == name.removeColor().length + 4) { + name = name.substring(2) + } + + val visitor = VisitorAPI.getOrCreateVisitor(name) ?: return + + visitor.entityId = lastClickedNpc + visitor.offer = visitorOffer + VisitorOpenEvent(visitor).postAndCatch() + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + VisitorAPI.inVisitorInventory = false + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onStackClick(event: SlotClickEvent) { + if (!VisitorAPI.inVisitorInventory) return + if (event.clickType != 0) return + + val visitor = VisitorAPI.getVisitor(lastClickedNpc) ?: return + + if (event.slotId == VISITOR_REFUSE_ITEM_SLOT) { + if (event.slot.stack?.name != "§cRefuse Offer") return + + visitor.hasReward()?.let { + if (config.rewardWarning.preventRefusing) { + if (config.rewardWarning.bypassKey.isKeyHeld()) { + LorenzUtils.chat("§e[SkyHanni] §cBypassed blocking refusal of visitor ${visitor.visitorName} §7(${it.displayName}§7)") + return + } + event.isCanceled = true + LorenzUtils.chat("§e[SkyHanni] §cBlocked refusing visitor ${visitor.visitorName} §7(${it.displayName}§7)") + if (config.rewardWarning.bypassKey == Keyboard.KEY_NONE) { + LorenzUtils.clickableChat( + "§eIf you want to deny this visitor, set a keybind in §e/sh bypass", + "sh bypass" + ) + } + Minecraft.getMinecraft().thePlayer.closeScreen() + return + } + } + + VisitorAPI.changeStatus(visitor, VisitorStatus.REFUSED, "refused") + return + } + if (event.slotId == VISITOR_ACCEPT_ITEM_SLOT && event.slot.stack?.getLore()?.any { it == "§eClick to give!" } == true) { + VisitorAPI.changeStatus(visitor, VisitorStatus.ACCEPTED, "accepted") + return + } + } + + @SubscribeEvent(priority = EventPriority.HIGH) + fun onTooltip(event: ItemTooltipEvent) { + if (!GardenAPI.onBarnPlot) return + if (!VisitorAPI.inVisitorInventory) return + val visitor = VisitorAPI.getVisitor(lastClickedNpc) ?: return + VisitorToolTipEvent(visitor, event.itemStack, event.toolTip).postAndCatch() + } + + @SubscribeEvent + fun onCheckRender(event: CheckRenderEntityEvent<*>) { + if (!GardenAPI.inGarden()) return + if (!GardenAPI.onBarnPlot) return + if (config.highlightStatus != 1 && config.highlightStatus != 2) return + + val entity = event.entity + if (entity is EntityArmorStand && entity.name == "§e§lCLICK") { + event.isCanceled = true + } + } + + @SubscribeEvent + fun onRenderWorld(event: LorenzRenderWorldEvent) { + if (!GardenAPI.inGarden()) return + if (!GardenAPI.onBarnPlot) return + if (config.highlightStatus != 1 && config.highlightStatus != 2) return + + for (visitor in VisitorAPI.getVisitors()) { + visitor.getNameTagEntity()?.let { + if (it.distanceToPlayer() > 15) return@let + VisitorRenderEvent(visitor, event.exactLocation(it), event).postAndCatch() + } + } + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorTooltipParser.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorTooltipParser.kt new file mode 100644 index 000000000..5d6e7ee26 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorTooltipParser.kt @@ -0,0 +1,42 @@ +package at.hannibal2.skyhanni.features.garden.visitor + +import at.hannibal2.skyhanni.config.features.GardenConfig +import at.hannibal2.skyhanni.utils.ItemUtils + +class VisitorTooltipParser { + class ParsedTooltip( + val itemsNeeded: MutableMap<String, Int>, + val rewards: MutableMap<String, Int>, + val config: GardenConfig, + ) + + enum class ParsingSection { + ITEMS_NEEDED, + REWARDS + + } + + companion object { + fun parse(lore: List<String>, config: GardenConfig?): ParsedTooltip { + var section = ParsingSection.ITEMS_NEEDED + val parsedData = ParsedTooltip(mutableMapOf(), mutableMapOf(), config ?: GardenConfig()) + for (line in lore) { + if (line.isBlank()) continue + val isRewardSection = line.contains("Rewards:") + if (isRewardSection) { + section = ParsingSection.REWARDS + continue + } + + val (itemName, amount) = ItemUtils.readItemAmount(line) ?: continue + + when (section) { + ParsingSection.ITEMS_NEEDED -> parsedData.itemsNeeded[itemName] = amount + ParsingSection.REWARDS -> parsedData.rewards[itemName] = amount + } + } + + return parsedData; + } + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt index 94c20c2ed..7e015b09c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/HideNotClickableItems.kt @@ -9,6 +9,7 @@ import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.features.bazaar.BazaarApi import at.hannibal2.skyhanni.features.garden.composter.ComposterOverlay import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorFeatures +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.features.rift.RiftAPI.motesNpcPrice import at.hannibal2.skyhanni.utils.InventoryUtils @@ -385,7 +386,7 @@ class HideNotClickableItems { private fun hideNpcSell(chestName: String, stack: ItemStack): Boolean { if (!tradeNpcFilter.match(chestName)) return false - if (GardenVisitorFeatures.inVisitorInventory) return false + if (VisitorAPI.inVisitorInventory) return false reverseColor = true var name = stack.cleanName() diff --git a/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorAPITest.kt b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorAPITest.kt new file mode 100644 index 000000000..74baf866a --- /dev/null +++ b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorAPITest.kt @@ -0,0 +1,51 @@ +package at.hannibal2.skyhanni.test.garden + +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI +import org.junit.jupiter.api.Test + +class VisitorAPITest { + + @Test + fun testFromHypixelName() { + assert(VisitorAPI.fromHypixelName(" §r Jacob") == "§fJacob") + assert(VisitorAPI.fromHypixelName("§r Jacob") == "§fJacob") + assert(VisitorAPI.fromHypixelName("§rJacob") == "§fJacob") + assert(VisitorAPI.fromHypixelName("Jacob") == "§fJacob") + assert(VisitorAPI.fromHypixelName(" Jacob ") == "§fJacob") + assert(VisitorAPI.fromHypixelName("§cSpaceman") == "§cSpaceman") + assert(VisitorAPI.fromHypixelName("§cGrandma Wolf") == "§cGrandma Wolf") + } + + @Test + fun testIsVisitorInfo() { + + // To short + assert( + VisitorAPI.isVisitorInfo(mutableListOf( + "§a§lVisitor Info", + "§7§oClick to view info about this visitor." + )) == false + ) + + // To long + assert( + VisitorAPI.isVisitorInfo(mutableListOf( + "§a§lVisitor Info", + "§7§oClick to view info about this visitor.", + "§7§oClick to view info about this visitor.", + "§7§oClick to view info about this visitor.", + "§7§oClick to view info about this visitor.", + )) == false + ) + + // Third line is §7Offers Accepted: §a + assert( + VisitorAPI.isVisitorInfo(mutableListOf( + "§a§lVisitor Info", + "§7§oClick to view info about this visitor.", + "§7§oClick to view info about this visitor.", + "§7Offers Accepted: §a", + )) == true + ) + } +}
\ No newline at end of file diff --git a/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorListenerTest.kt b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorListenerTest.kt new file mode 100644 index 000000000..13e96a019 --- /dev/null +++ b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorListenerTest.kt @@ -0,0 +1,83 @@ +package at.hannibal2.skyhanni.test.garden + +import at.hannibal2.skyhanni.events.TabListUpdateEvent +import at.hannibal2.skyhanni.features.garden.GardenAPI +import at.hannibal2.skyhanni.features.garden.visitor.VisitorAPI +import at.hannibal2.skyhanni.features.garden.visitor.VisitorListener +import at.hannibal2.skyhanni.utils.LorenzUtils +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkObject +import io.mockk.verify +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + + +class VisitorListenerTest { + private lateinit var listener: VisitorListener + @BeforeEach + fun setUp() { + mockkObject(GardenAPI) + every { GardenAPI.inGarden() } returns true + + mockkObject(LorenzUtils) + every { LorenzUtils.getPlayerName() } returns "ThePlayerName" + + mockkObject(VisitorAPI) + every { VisitorAPI.addVisitor(any()) } returns true + + listener = VisitorListener() + } + + @Test + fun `onTablistUpdate it should add new visitors to the list`() { + listener.onTabListUpdate( + TabListUpdateEvent(mutableListOf( + "§b§lVisitors:", + "§cSpaceman", + "§cGrandma Wolf", + "ThePlayerName", + "Jacob", + "", + )) + ) + + verify { VisitorAPI.addVisitor("§fJacob") } + verify { VisitorAPI.addVisitor("§cSpaceman") } + verify { VisitorAPI.addVisitor("§cGrandma Wolf") } + } + + @Test + fun `onTablistUpdate it should remove visitors from the list`() { + every { VisitorAPI.getVisitors() } returns listOf( + mockk { every { visitorName } returns "§fJacob" }, + ) + + listener.onTabListUpdate( + TabListUpdateEvent(mutableListOf( + "§b§lVisitors:", + "", + )) + ) + + verify { VisitorAPI.removeVisitor("§fJacob") } + } + + @Test + fun `onTablistUpdate it should not remove visitors if the timeout is not hit`() { + every { VisitorAPI.getVisitors() } returns listOf( + mockk { every { visitorName } returns "§fJacob" }, + ) + + every { LorenzUtils.lastWorldSwitch } returns System.currentTimeMillis() + + listener.onTabListUpdate( + TabListUpdateEvent(mutableListOf( + "§b§lVisitors:", + "", + )) + ) + + verify(exactly = 0) { VisitorAPI.removeVisitor("§fJacob") } + } +}
\ No newline at end of file diff --git a/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorToolTipParserTest.kt b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorToolTipParserTest.kt new file mode 100644 index 000000000..9418b3db8 --- /dev/null +++ b/src/test/java/at/hannibal2/skyhanni/test/garden/VisitorToolTipParserTest.kt @@ -0,0 +1,65 @@ +package at.hannibal2.skyhanni.test.garden + +import at.hannibal2.skyhanni.config.features.GardenConfig +import at.hannibal2.skyhanni.features.garden.visitor.VisitorTooltipParser +import org.junit.jupiter.api.Test + +class VisitorToolTipParserTest { + private val lore = mutableListOf( + "§7Items Required:", + " §aEnchanted Hay Bale §8x28", + "", + "§7Rewards:", + " §8+§37.2k §7Farming XP", + " §8+§215 §7Garden Experience", + " §8+§c23 Copper", + " §8+§b10 Bits", + " §aJacob's Ticket", + " §9Flowering Bouquet", + "", + "§eClick to give!" + ) + + @Test + fun testParseItemsNeeded() { + val parsedData = VisitorTooltipParser.parse(lore, GardenConfig()) + assert(parsedData.itemsNeeded.isNotEmpty()) { + "Visitor items needed is ${parsedData.itemsNeeded.count()} instead of 1" + } + assert(parsedData.itemsNeeded.get("§aEnchanted Hay Bale") == 28) { + "Visitor items needed does not contain '§aEnchanted Hay Bale'" + } + } + + @Test + fun testParseRewards() { + val parsedData = VisitorTooltipParser.parse(lore, GardenConfig()) + assert(parsedData.rewards.isNotEmpty()) { + "Visitor rewards is ${parsedData.rewards.count()} instead of 6" + } + + val assertions = mutableMapOf( + "§7Farming XP" to 7200, + "§7Garden Experience" to 15, + "Copper" to 23, + "Bits" to 10, + "§aJacob's Ticket" to 1, + "§9Flowering Bouquet" to 1 + ) + + for ((itemName, amount) in assertions) { + assert(parsedData.rewards.get(itemName) == amount) { + "Visitor rewards does not contain '$itemName' with amount '$amount'" + } + } + } + + @Test + fun testParseCopper() { + val parsedData = VisitorTooltipParser.parse(lore, GardenConfig()) + val copper = parsedData.rewards.get("Copper") + assert(copper == 23) { + "Visitor rewards does not contain 'Copper' with amount '23'" + } + } +}
\ No newline at end of file |