From 55c2614cb69551363607cbdb7f42c38eccd3d38e Mon Sep 17 00:00:00 2001
From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com>
Date: Tue, 9 May 2023 06:53:45 +1000
Subject: Trevor features and solver (#92)

---
 src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt |   4 +
 .../hannibal2/skyhanni/config/features/Misc.java   |  35 ++-
 .../at/hannibal2/skyhanni/data/GuiEditManager.kt   |   2 -
 .../garden/farming/GardenCustomKeybinds.kt         |  54 +++--
 .../features/misc/trevor/CurrentMobArea.kt         |  14 ++
 .../features/misc/trevor/TrevorFeatures.kt         | 234 +++++++++++++++++++++
 .../skyhanni/features/misc/trevor/TrevorSolver.kt  |  86 ++++++++
 .../mixins/transformers/AccessorKeyBinding.java    |   5 -
 .../mixins/transformers/MixinKeyBinding.java       |  10 +-
 .../java/at/hannibal2/skyhanni/utils/NEUItems.kt   |   3 +-
 10 files changed, 411 insertions(+), 36 deletions(-)
 create mode 100644 src/main/java/at/hannibal2/skyhanni/features/misc/trevor/CurrentMobArea.kt
 create mode 100644 src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorFeatures.kt
 create mode 100644 src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorSolver.kt

(limited to 'src')

diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
index ecdf57a06..1d92800c7 100644
--- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
+++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt
@@ -46,6 +46,8 @@ import at.hannibal2.skyhanni.features.misc.*
 import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager
 import at.hannibal2.skyhanni.features.misc.tiarelay.TiaRelayHelper
 import at.hannibal2.skyhanni.features.misc.tiarelay.TiaRelayWaypoints
+import at.hannibal2.skyhanni.features.misc.trevor.TrevorFeatures
+import at.hannibal2.skyhanni.features.misc.trevor.TrevorSolver
 import at.hannibal2.skyhanni.features.misc.update.UpdateManager
 import at.hannibal2.skyhanni.features.mobs.AreaMiniBossFeatures
 import at.hannibal2.skyhanni.features.mobs.AshfangMinisNametagHider
@@ -267,6 +269,8 @@ class SkyHanniMod {
         loadModule(GardenRecentTeleportPadsDisplay())
         loadModule(InquisitorWaypointShare)
         loadModule(CopyNearbyParticlesCommand)
+        loadModule(TrevorFeatures())
+        loadModule(TrevorSolver)
 
         init()
 
diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
index f3dd78b37..fdcd643d9 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
+++ b/src/main/java/at/hannibal2/skyhanni/config/features/Misc.java
@@ -231,6 +231,9 @@ public class Misc {
     @ConfigAccordionId(id = 11)
     public boolean estimatedIemValueAlwaysEnabled = true;
 
+    @Expose
+    public Position itemPriceDataPos = new Position(140, 90, false, true);
+
     @ConfigOption(name = "Discord Rich Presence", desc = "")
     @Accordion
     @Expose
@@ -305,8 +308,38 @@ public class Misc {
         public Property<Integer> auto = Property.of(0);
     }
 
+    @ConfigOption(name = "Trevor The Trapper", desc = "")
+    @Accordion
     @Expose
-    public Position itemPriceDataPos = new Position(140, 90, false, true);
+    public TrevorTheTrapper trevorTheTrapper = new TrevorTheTrapper();
+
+    public static class TrevorTheTrapper {
+
+        @Expose
+        @ConfigOption(name = "Trapper Solver", desc = "Assists you in finding Trevor's mobs. §cMay not always work as expected.")
+        @ConfigEditorBoolean
+        public boolean trapperSolver = true;
+
+        @Expose
+        @ConfigOption(name = "Mob Dead Warning", desc = "Show a message when Trevor's mob dies.")
+        @ConfigEditorBoolean
+        public boolean trapperMobDiedMessage = true;
+
+        @Expose
+        @ConfigOption(name = "Warp to Trapper", desc = "Warp to Trevor's Den.")
+        @ConfigEditorBoolean
+        public boolean warpToTrapper = false;
+
+        @Expose
+        @ConfigOption(name = "Warp Hotkey", desc = "Press this key to warp to Trevor's Den.")
+        @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
+        public int keyBindWarpTrapper = Keyboard.KEY_NONE;
+
+        @Expose
+        @ConfigOption(name = "Trapper Cooldown", desc = "Change the color of Trevor and adds a cooldown over his head.")
+        @ConfigEditorBoolean
+        public boolean trapperTalkCooldown = true;
+    }
 
     @Expose
     @ConfigOption(name = "Exp Bottles", desc = "Hides all the experience orbs lying on the ground.")
diff --git a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt
index 7e6e06c80..54ff70886 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt
@@ -6,7 +6,6 @@ import at.hannibal2.skyhanni.config.core.config.gui.GuiPositionEditor
 import at.hannibal2.skyhanni.events.GuiRenderEvent
 import at.hannibal2.skyhanni.utils.LorenzUtils
 import at.hannibal2.skyhanni.utils.NEUItems
-import io.github.moulberry.notenoughupdates.NEUOverlay
 import net.minecraft.client.Minecraft
 import net.minecraft.client.gui.inventory.GuiChest
 import net.minecraft.client.gui.inventory.GuiEditSign
@@ -33,7 +32,6 @@ class GuiEditManager {
         val key = if (Keyboard.getEventKey() == 0) Keyboard.getEventCharacter().code + 256 else Keyboard.getEventKey()
         if (SkyHanniMod.feature.gui.keyBindOpen != key) return
 
-        if (NEUOverlay.searchBarHasFocus) return
         if (NEUItems.neuHasFocus()) return
 
         if (isInGui()) return
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt
index a96ccf62c..b920cdba6 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCustomKeybinds.kt
@@ -2,13 +2,15 @@ package at.hannibal2.skyhanni.features.garden.farming
 
 import at.hannibal2.skyhanni.SkyHanniMod
 import at.hannibal2.skyhanni.config.features.Garden
-import at.hannibal2.skyhanni.events.GardenToolChangeEvent
 import at.hannibal2.skyhanni.features.garden.GardenAPI
 import at.hannibal2.skyhanni.mixins.transformers.AccessorKeyBinding
 import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.inventory.GuiEditSign
 import net.minecraft.client.settings.KeyBinding
-import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import org.lwjgl.input.Keyboard
+import org.lwjgl.input.Mouse
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
 import java.util.*
 
 object GardenCustomKeybinds {
@@ -16,7 +18,7 @@ object GardenCustomKeybinds {
     private val mcSettings get() = Minecraft.getMinecraft().gameSettings
 
     private val map: MutableMap<KeyBinding, () -> Int> = IdentityHashMap()
-    private val cache: MutableMap<Int, Boolean> = mutableMapOf()
+    private var lastWindowOpenTime = 0L
 
     init {
         map[mcSettings.keyBindAttack] = { shConfig.keyBindAttack }
@@ -31,35 +33,47 @@ object GardenCustomKeybinds {
 
     private fun isEnabled() = GardenAPI.inGarden() && shConfig.keyBindEnabled
 
-    private fun isActive() = isEnabled() && GardenAPI.toolInHand != null
+    private fun isActive(): Boolean {
+        if (!isEnabled()) return false
+        if (GardenAPI.toolInHand == null) return false
 
-    @SubscribeEvent
-    fun onToolChange(event: GardenToolChangeEvent) {
-        map.forEach { (keyBinding, override) ->
-            keyBinding as AccessorKeyBinding
-            val keyCode = if (isActive()) override() else keyBinding.keyCode
-            keyBinding.pressed_skyhanni = cache[keyCode] ?: false
+        if (Minecraft.getMinecraft().currentScreen != null) {
+            if (Minecraft.getMinecraft().currentScreen is GuiEditSign) {
+                lastWindowOpenTime = System.currentTimeMillis()
+            }
+            return false
+        }
+
+        // TODO remove workaround
+        if (System.currentTimeMillis() < lastWindowOpenTime + 300) return false
+
+        return true
+    }
+
+    private fun isHeld(keyCode: Int): Boolean {
+        if (keyCode == 0) return false
+        return if (keyCode < 0) {
+            Mouse.isButtonDown(keyCode + 100)
+        } else {
+            Keyboard.isKeyDown(keyCode)
         }
     }
 
     @JvmStatic
-    fun onTick(keyCode: Int, ci: CallbackInfo) {
-        if (keyCode == 0) return
+    fun isKeyDown(keyBinding: KeyBinding, cir: CallbackInfoReturnable<Boolean>) {
         if (!isActive()) return
-        val keyBinding = map.entries.firstOrNull { it.value() == keyCode }?.key ?: return
-        ci.cancel()
-        keyBinding as AccessorKeyBinding
-        keyBinding.pressTime_skyhanni++
+        val override = map[keyBinding] ?: return
+        val keyCode = override()
+        cir.returnValue = isHeld(keyCode)
     }
 
     @JvmStatic
-    fun setKeyBindState(keyCode: Int, pressed: Boolean, ci: CallbackInfo) {
-        if (keyCode == 0) return
-        cache[keyCode] = pressed
+    fun onTick(keyCode: Int, ci: CallbackInfo) {
         if (!isActive()) return
+        if (keyCode == 0) return
         val keyBinding = map.entries.firstOrNull { it.value() == keyCode }?.key ?: return
         ci.cancel()
         keyBinding as AccessorKeyBinding
-        keyBinding.pressed_skyhanni = pressed
+        keyBinding.pressTime_skyhanni++
     }
 }
\ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/CurrentMobArea.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/CurrentMobArea.kt
new file mode 100644
index 000000000..fcc083bc7
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/CurrentMobArea.kt
@@ -0,0 +1,14 @@
+package at.hannibal2.skyhanni.features.misc.trevor
+
+import at.hannibal2.skyhanni.utils.LorenzVec
+
+enum class CurrentMobArea(val location: String, val coordinates: LorenzVec) {
+    OASIS("Oasis", LorenzVec(126.0, 77.0, -456.0)),
+    GORGE("Mushroom Gorge", LorenzVec(300.0, 80.0, -509.0)),
+    OVERGROWN("Overgrown Mushroom Cave", LorenzVec(242.0, 60.0, -389.0)),
+    SETTLEMENT("Desert Settlement", LorenzVec(184.0, 86.0, -384.0)),
+    GLOWING("Glowing Mushroom Cave", LorenzVec(199.0, 50.0, -512.0)),
+    MOUNTAIN("Desert Mountain", LorenzVec(255.0, 148.0, -518.0)),
+    FOUND("Mob Location", LorenzVec(0.0, 0.0, 0.0)),
+    NONE("   ", LorenzVec(0.0, 0.0, 0.0)),
+}
\ No newline at end of file
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorFeatures.kt
new file mode 100644
index 000000000..69a5a0548
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorFeatures.kt
@@ -0,0 +1,234 @@
+package at.hannibal2.skyhanni.features.misc.trevor
+
+import at.hannibal2.skyhanni.SkyHanniMod
+import at.hannibal2.skyhanni.data.IslandType
+import at.hannibal2.skyhanni.data.ScoreboardData
+import at.hannibal2.skyhanni.data.TitleUtils
+import at.hannibal2.skyhanni.events.CheckRenderEntityEvent
+import at.hannibal2.skyhanni.events.LorenzChatEvent
+import at.hannibal2.skyhanni.events.withAlpha
+import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper
+import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled
+import at.hannibal2.skyhanni.utils.*
+import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer
+import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText
+import at.hannibal2.skyhanni.utils.RenderUtils.drawString
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.StringUtils.removeColor
+import net.minecraft.client.Minecraft
+import net.minecraft.client.gui.inventory.GuiChest
+import net.minecraft.client.gui.inventory.GuiEditSign
+import net.minecraft.client.gui.inventory.GuiInventory
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.item.EntityArmorStand
+import net.minecraftforge.client.event.RenderWorldLastEvent
+import net.minecraftforge.event.world.WorldEvent
+import net.minecraftforge.fml.common.eventhandler.EventPriority
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
+import net.minecraftforge.fml.common.gameevent.TickEvent
+import org.lwjgl.input.Keyboard
+import kotlin.concurrent.fixedRateTimer
+
+
+class TrevorFeatures {
+    private val trapperPattern =
+        "\\[NPC] Trevor: You can find your (?<rarity>.*) animal near the (?<location>.*).".toPattern()
+    private val talbotPatternAbove =
+        "The target is around (?<height>.*) blocks above, at a (?<angle>.*) degrees angle!".toPattern()
+    private val talbotPatternBelow =
+        "The target is around (?<height>.*) blocks below, at a (?<angle>.*) degrees angle!".toPattern()
+    private val locationPattern = "Zone: (?<zone>.*)".toPattern()
+    private var timeUntilNextReady = 0
+    private var trapperReady: Boolean = true
+    private var currentStatus = TrapperStatus.READY
+    private var currentLabel = "§2Ready"
+    private var trapperID: Int = 56
+    private var backupTrapperID: Int = 17
+    private var timeLastWarped: Long = 0
+
+    private val config get() = SkyHanniMod.feature.misc.trevorTheTrapper
+
+    init {
+        fixedRateTimer(name = "skyhanni-update-trapper", period = 1000L) {
+            if (onFarmingIsland()) {
+                updateTrapper()
+                TrevorSolver.findMob()
+            }
+        }
+    }
+
+    @SubscribeEvent
+    fun onChat(event: LorenzChatEvent) {
+        if (!onFarmingIsland()) return
+        if (event.message == "§aReturn to the Trapper soon to get a new animal to hunt!") {
+            TrevorSolver.resetLocation()
+            if (config.trapperMobDiedMessage) {
+                TitleUtils.sendTitle("§2Mob Died ", 5_000)
+                SoundUtils.playBeepSound()
+            }
+            trapperReady = true
+            TrevorSolver.mobLocation = CurrentMobArea.NONE
+            if (timeUntilNextReady <= 0) {
+                currentStatus = TrapperStatus.READY
+                currentLabel = "§2Ready"
+            } else {
+                currentStatus = TrapperStatus.WAITING
+                currentLabel = "§3$timeUntilNextReady seconds left"
+            }
+        }
+
+        var matcher = trapperPattern.matcher(event.message.removeColor())
+        if (matcher.matches()) {
+            timeUntilNextReady = 61
+            currentStatus = TrapperStatus.ACTIVE
+            currentLabel = "§cActive Quest"
+            trapperReady = false
+        }
+
+        matcher = talbotPatternAbove.matcher(event.message.removeColor())
+        if (matcher.matches()) {
+            val height = matcher.group("height").toInt()
+            TrevorSolver.findMobHeight(height, true)
+        }
+
+        matcher = talbotPatternBelow.matcher(event.message.removeColor())
+        if (matcher.matches()) {
+            val height = matcher.group("height").toInt()
+            TrevorSolver.findMobHeight(height, false)
+        }
+    }
+
+    private fun updateTrapper() {
+        timeUntilNextReady -= 1
+        if (trapperReady && timeUntilNextReady > 0) {
+            currentStatus = TrapperStatus.WAITING
+            currentLabel = "§3$timeUntilNextReady seconds left"
+        }
+
+        if (timeUntilNextReady <= 0 && trapperReady) {
+            if (timeUntilNextReady == 0) {
+                TitleUtils.sendTitle("§2Trapper Ready ", 3_000)
+                SoundUtils.playBeepSound()
+            }
+            currentStatus = TrapperStatus.READY
+            currentLabel = "§2Ready"
+        }
+
+        var found = false
+        var active = false
+        val previousLocation = TrevorSolver.mobLocation
+        for (line in TabListData.getTabList()) {
+            val formattedLine = line.removeColor().drop(1)
+            if (formattedLine.startsWith("Time Left: ")) {
+                trapperReady = false
+                currentStatus = TrapperStatus.ACTIVE
+                currentLabel = "§cActive Quest"
+                active = true
+            }
+
+            CurrentMobArea.values().firstOrNull { it.location == formattedLine }?.let {
+                TrevorSolver.mobLocation = it
+                found = true
+            }
+            locationPattern.matchMatcher(formattedLine) {
+                val zone = group("zone")
+                TrevorSolver.mobLocation = CurrentMobArea.values().firstOrNull { it.location == zone }
+                    ?: CurrentMobArea.NONE
+                found = true
+            }
+        }
+        if (!found) TrevorSolver.mobLocation = CurrentMobArea.NONE
+        if (!active) {
+            trapperReady = true
+        }
+        if (TrevorSolver.mobCoordinates != LorenzVec(0.0, 0.0, 0.0) && active) {
+            TrevorSolver.mobLocation = previousLocation
+        }
+    }
+
+    @SubscribeEvent
+    fun onRenderWorld(event: RenderWorldLastEvent) {
+        if (!onFarmingIsland()) return
+        var entityTrapper = Minecraft.getMinecraft().theWorld.getEntityByID(trapperID)
+        if (entityTrapper !is EntityLivingBase) entityTrapper =
+            Minecraft.getMinecraft().theWorld.getEntityByID(backupTrapperID)
+        if (entityTrapper is EntityLivingBase) {
+            if (config.trapperTalkCooldown) {
+                RenderLivingEntityHelper.setEntityColor(
+                    entityTrapper,
+                    currentStatus.color
+                ) { config.trapperTalkCooldown }
+                entityTrapper.getLorenzVec().let {
+                    if (it.distanceToPlayer() < 15) {
+                        event.drawString(it.add(0.0, 2.23, 0.0), currentLabel)
+                    }
+                }
+            }
+        }
+
+        if (config.trapperSolver) {
+            var location = TrevorSolver.mobLocation.coordinates
+            if (TrevorSolver.mobLocation == CurrentMobArea.NONE) return
+            if (TrevorSolver.averageHeight != 0.0) {
+                location = LorenzVec(location.x, TrevorSolver.averageHeight, location.z)
+            }
+            if (TrevorSolver.mobLocation == CurrentMobArea.FOUND) {
+                location = TrevorSolver.mobCoordinates
+                event.drawWaypointFilled(location.add(0, -2, 0), LorenzColor.GREEN.toColor(), true, true)
+                event.drawDynamicText(location.add(0, 2, 0), TrevorSolver.mobLocation.location, 1.5)
+            } else {
+                event.drawWaypointFilled(location, LorenzColor.GOLD.toColor(), true, true)
+                event.drawDynamicText(location.add(0, 1, 0), TrevorSolver.mobLocation.location, 1.5)
+            }
+        }
+    }
+
+    @SubscribeEvent
+    fun onTick(event: TickEvent.ClientTickEvent) {
+        if (!config.warpToTrapper) return
+        if (!Keyboard.getEventKeyState()) return
+        val key = if (Keyboard.getEventKey() == 0) Keyboard.getEventCharacter().code + 256 else Keyboard.getEventKey()
+        if (config.keyBindWarpTrapper != key) return
+
+        if (!LorenzUtils.inSkyBlock || LorenzUtils.inDungeons || LorenzUtils.inKuudraFight) return
+
+        Minecraft.getMinecraft().currentScreen?.let {
+            if (it !is GuiInventory && it !is GuiChest && it !is GuiEditSign) return
+        }
+        if (NEUItems.neuHasFocus()) return
+
+        if (System.currentTimeMillis() - timeLastWarped < 3000) return
+        LorenzUtils.sendCommandToServer("warp trapper")
+        timeLastWarped = System.currentTimeMillis()
+    }
+
+    @SubscribeEvent(priority = EventPriority.HIGHEST)
+    fun onCheckRender(event: CheckRenderEntityEvent<*>) {
+        if (!inTrapperDen()) return
+        if (!config.trapperTalkCooldown) return
+        val entity = event.entity
+        if (entity is EntityArmorStand) {
+            if (entity.name == "§e§lCLICK") {
+                event.isCanceled = true
+            }
+        }
+    }
+
+    @SubscribeEvent
+    fun onWorldChange(event: WorldEvent.Load) {
+        TrevorSolver.resetLocation()
+        currentStatus = TrapperStatus.READY
+        currentLabel = "§2Ready"
+    }
+
+    enum class TrapperStatus(val color: Int) {
+        READY(LorenzColor.DARK_GREEN.toColor().withAlpha(75)),
+        WAITING(LorenzColor.DARK_AQUA.toColor().withAlpha(75)),
+        ACTIVE(LorenzColor.DARK_RED.toColor().withAlpha(75)),
+    }
+
+    private fun onFarmingIsland() =
+        LorenzUtils.inSkyBlock && LorenzUtils.skyBlockIsland == IslandType.THE_FARMING_ISLANDS
+
+    private fun inTrapperDen() = ScoreboardData.sidebarLinesFormatted.contains(" §7⏣ §bTrapper's Den")
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorSolver.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorSolver.kt
new file mode 100644
index 000000000..3d6c91417
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/features/misc/trevor/TrevorSolver.kt
@@ -0,0 +1,86 @@
+package at.hannibal2.skyhanni.features.misc.trevor
+
+import at.hannibal2.skyhanni.utils.LocationUtils
+import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth
+import at.hannibal2.skyhanni.utils.LorenzVec
+import at.hannibal2.skyhanni.utils.toLorenzVec
+import net.minecraft.client.Minecraft
+import net.minecraft.entity.EntityLivingBase
+import net.minecraft.entity.item.EntityArmorStand
+
+object TrevorSolver {
+    private val animalNames = arrayOf("Cow", "Horse", "Sheep", "Pig", "Rabbit", "Chicken")
+
+    private var maxHeight: Double = 0.0
+    private var minHeight: Double = 0.0
+    private var foundID = -1
+    var mobCoordinates = LorenzVec(0.0, 0.0, 0.0)
+    var mobLocation = CurrentMobArea.NONE
+    var averageHeight = (minHeight + maxHeight) / 2
+
+    fun findMobHeight(height: Int, above: Boolean) {
+        val playerPosition = LocationUtils.playerLocation().round(2)
+        val mobHeight = if (above) playerPosition.y + height else playerPosition.y - height
+        if (maxHeight == 0.0) {
+
+            maxHeight = mobHeight + 2.5
+            minHeight = mobHeight - 2.5
+        } else {
+            if (mobHeight + 2.5 in minHeight..maxHeight) {
+                maxHeight = mobHeight + 2.5
+            } else if (mobHeight - 2.5 in minHeight..maxHeight) {
+                minHeight = mobHeight - 2.5
+            } else {
+                maxHeight = mobHeight + 2.5
+                minHeight = mobHeight - 2.5
+            }
+        }
+        averageHeight = (minHeight + maxHeight) / 2
+    }
+
+    fun findMob() {
+        val world = Minecraft.getMinecraft().theWorld ?: return
+        for (entity in world.getLoadedEntityList()) {
+            val name = entity.name
+            // looking at 2 diff entities rn
+            val entityHealth = if (entity is EntityLivingBase) entity.baseMaxHealth else 0
+            if (intArrayOf(100, 500, 1000, 5000, 10000).any { it == entityHealth }) {
+                if (animalNames.any { it == name }) {
+                    if (LocationUtils.canSee(LocationUtils.playerLocation(), entity.position.toLorenzVec())) {
+                        if (entity.isInvisibleToPlayer(Minecraft.getMinecraft().thePlayer)) return
+
+                        if (foundID == entity.entityId) {
+                            mobLocation = CurrentMobArea.FOUND
+                            mobCoordinates = entity.position.toLorenzVec()
+                        } else {
+                            foundID = entity.entityId
+                        }
+                        return
+                    }
+                }
+            }
+
+            if (entity is EntityArmorStand) {
+                for (animal in animalNames) {
+                    if (name.contains(animal)) {
+                        if (foundID == entity.entityId) {
+                            mobLocation = CurrentMobArea.FOUND
+                            mobCoordinates = entity.position.toLorenzVec()
+                        } else {
+                            foundID = entity.entityId
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fun resetLocation() {
+        maxHeight = 0.0
+        minHeight = 0.0
+        averageHeight = (minHeight + maxHeight) / 2
+        foundID = -1
+        mobCoordinates = LorenzVec(0.0, 0.0, 0.0)
+    }
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java
index a06f3c339..53abc49dc 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/AccessorKeyBinding.java
@@ -7,11 +7,6 @@ import org.spongepowered.asm.mixin.gen.Invoker;
 
 @Mixin(KeyBinding.class)
 public interface AccessorKeyBinding {
-    @Accessor("pressed")
-    boolean getPressed_skyhanni();
-
-    @Accessor("pressed")
-    void setPressed_skyhanni(boolean newVal);
 
     @Accessor("pressTime")
     int getPressTime_skyhanni();
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java
index 8862b57e4..35a9bc780 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/MixinKeyBinding.java
@@ -3,7 +3,6 @@ package at.hannibal2.skyhanni.mixins.transformers;
 import at.hannibal2.skyhanni.features.garden.farming.GardenCustomKeybinds;
 import net.minecraft.client.settings.KeyBinding;
 import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -11,16 +10,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 @Mixin(KeyBinding.class)
 public class MixinKeyBinding {
-    @Shadow private int keyCode;
-
     @Inject(method = "onTick", at = @At("HEAD"), cancellable = true)
     private static void noOnTick(int keyCode, CallbackInfo ci) {
         GardenCustomKeybinds.onTick(keyCode, ci);
     }
 
-    @Inject(method = "setKeyBindState", at = @At("HEAD"), cancellable = true)
-    private static void nosetKeyBindState(int keyCode, boolean pressed, CallbackInfo ci) {
-        GardenCustomKeybinds.setKeyBindState(keyCode, pressed, ci);
+    @Inject(method = "isKeyDown", at = @At("HEAD"), cancellable = true)
+    public void noIsKeyDown(CallbackInfoReturnable<Boolean> cir) {
+        GardenCustomKeybinds.isKeyDown((KeyBinding) (Object) this, cir);
     }
-
 }
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
index d605c294e..7fbb70539 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
@@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName
 import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal
 import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
 import io.github.moulberry.notenoughupdates.NEUManager
+import io.github.moulberry.notenoughupdates.NEUOverlay
 import io.github.moulberry.notenoughupdates.NotEnoughUpdates
 import io.github.moulberry.notenoughupdates.overlays.AuctionSearchOverlay
 import io.github.moulberry.notenoughupdates.overlays.BazaarSearchOverlay
@@ -219,11 +220,11 @@ object NEUItems {
         return recipes
     }
 
-    // TODO add support for neu item list
     fun neuHasFocus(): Boolean {
         if (AuctionSearchOverlay.shouldReplace()) return true
         if (BazaarSearchOverlay.shouldReplace()) return true
         if (InventoryUtils.inStorage()) return true
+        if (NEUOverlay.searchBarHasFocus) return true
 
         return false
     }
-- 
cgit