From 66b98b62ec0ef0aa56d47af48131d661d43de579 Mon Sep 17 00:00:00 2001
From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com>
Date: Tue, 16 Apr 2024 02:34:51 +1000
Subject: Improvement: Code cleanup, bug fix and new functions (#1445)

---
 .../skyhanni/data/ChatClickActionManager.kt        | 17 +++++++--
 .../features/garden/AtmosphericFilterDisplay.kt    |  6 +--
 .../features/garden/GardenNextJacobContest.kt      |  8 +---
 .../java/at/hannibal2/skyhanni/utils/ChatUtils.kt  | 11 +++++-
 .../java/at/hannibal2/skyhanni/utils/DelayedRun.kt |  7 +++-
 .../at/hannibal2/skyhanni/utils/InventoryUtils.kt  |  4 ++
 .../at/hannibal2/skyhanni/utils/LocationUtils.kt   | 10 +++++
 .../java/at/hannibal2/skyhanni/utils/LorenzVec.kt  | 43 +++++++++++++++++++++-
 .../skyhanni/utils/MinecraftConsoleFilter.kt       |  3 ++
 .../java/at/hannibal2/skyhanni/utils/Season.kt     | 29 ---------------
 .../at/hannibal2/skyhanni/utils/SkyblockSeason.kt  | 29 +++++++++++++++
 11 files changed, 121 insertions(+), 46 deletions(-)
 delete mode 100644 src/main/java/at/hannibal2/skyhanni/utils/Season.kt
 create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/SkyblockSeason.kt

(limited to 'src')

diff --git a/src/main/java/at/hannibal2/skyhanni/data/ChatClickActionManager.kt b/src/main/java/at/hannibal2/skyhanni/data/ChatClickActionManager.kt
index 2dac5bf4a..3dc03c5f9 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/ChatClickActionManager.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/ChatClickActionManager.kt
@@ -1,14 +1,15 @@
 package at.hannibal2.skyhanni.data
 
 import at.hannibal2.skyhanni.utils.ChatUtils
+import at.hannibal2.skyhanni.utils.SimpleTimeMark
 import at.hannibal2.skyhanni.utils.StringUtils
 
 object ChatClickActionManager {
 
     private val actions = mutableListOf<ClickableAction>()
 
-    fun oneTimeClick(message: String, onClick: () -> Any) {
-        val action = ClickableAction(StringUtils.generateRandomId(), message, onClick)
+    fun oneTimeClick(message: String, onClick: () -> Any, expiresAt: SimpleTimeMark) {
+        val action = ClickableAction(StringUtils.generateRandomId(), message, onClick, expiresAt = expiresAt)
         actions.add(action)
         action.sendToChat()
     }
@@ -24,6 +25,10 @@ object ChatClickActionManager {
     }
 
     private fun ClickableAction.runAction() {
+        if (expiresAt.isInPast()) {
+            actions.remove(this)
+            return
+        }
         onClick()
         if (oneTime) {
             actions.remove(this)
@@ -32,5 +37,11 @@ object ChatClickActionManager {
 
     private fun getActionByToken(token: String) = actions.find { it.token == token }
 
-    class ClickableAction(val token: String, val message: String, val onClick: () -> Any, val oneTime: Boolean = true)
+    class ClickableAction(
+        val token: String,
+        val message: String,
+        val onClick: () -> Any,
+        val oneTime: Boolean = true,
+        val expiresAt: SimpleTimeMark = SimpleTimeMark.farFuture()
+    )
 }
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/AtmosphericFilterDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/AtmosphericFilterDisplay.kt
index dfd5c6533..80adc5658 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/AtmosphericFilterDisplay.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/AtmosphericFilterDisplay.kt
@@ -6,7 +6,7 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent
 import at.hannibal2.skyhanni.events.SecondPassedEvent
 import at.hannibal2.skyhanni.utils.LorenzUtils
 import at.hannibal2.skyhanni.utils.RenderUtils.renderString
-import at.hannibal2.skyhanni.utils.Season
+import at.hannibal2.skyhanni.utils.SkyblockSeason
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
 
 class AtmosphericFilterDisplay {
@@ -19,7 +19,7 @@ class AtmosphericFilterDisplay {
     fun onSecondPassed(event: SecondPassedEvent) {
         if (!isEnabled()) return
         if (!GardenAPI.inGarden() && !config.outsideGarden) return
-        display = drawDisplay(Season.getCurrentSeason() ?: return)
+        display = drawDisplay(SkyblockSeason.getCurrentSeason() ?: return)
     }
 
     @SubscribeEvent
@@ -32,7 +32,7 @@ class AtmosphericFilterDisplay {
         }
     }
 
-    private fun drawDisplay(season: Season): String = buildString {
+    private fun drawDisplay(season: SkyblockSeason): String = buildString {
         if (!config.onlyBuff) {
             append(season.getSeason(config.abbreviateSeason))
             append("§7: ")
diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt
index e6f72d38f..471fc7e35 100644
--- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt
+++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt
@@ -26,6 +26,7 @@ import at.hannibal2.skyhanni.utils.SimpleTimeMark
 import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark
 import at.hannibal2.skyhanni.utils.SoundUtils
 import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.StringUtils.matches
 import at.hannibal2.skyhanni.utils.StringUtils.removeColor
 import at.hannibal2.skyhanni.utils.TabListData
 import at.hannibal2.skyhanni.utils.TimeUtils.format
@@ -185,12 +186,7 @@ object GardenNextJacobContest {
     @SubscribeEvent
     fun onInventoryOpen(event: InventoryFullyOpenedEvent) {
         if (!config.display) return
-
-        val backItem = event.inventoryItems[48] ?: return
-        if (backItem.name != "§aGo Back") return
-        val lore = backItem.getLore()
-        if (lore.size != 1) return
-        if (lore[0] != "§7To Calendar and Events") return
+        if (!monthPattern.matches(event.inventoryName)) return
 
         inCalendar = true
 
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
index eaae104ac..b3861ce27 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/ChatUtils.kt
@@ -159,14 +159,21 @@ object ChatUtils {
      * Sends a message to the user that they can click and run an action
      * @param message The message to be sent
      * @param onClick The runnable to be executed when the message is clicked
+     * @param expireAt When the click action should expire, default never
      * @param prefix Whether to prefix the message with the chat prefix, default true
      * @param prefixColor Color that the prefix should be, default yellow (§e)
      *
      * @see CHAT_PREFIX
      */
-    fun clickableChat(message: String, onClick: () -> Any, prefix: Boolean = true, prefixColor: String = "§e") {
+    fun clickableChat(
+        message: String,
+        onClick: () -> Any,
+        expireAt: SimpleTimeMark = SimpleTimeMark.farFuture(),
+        prefix: Boolean = true,
+        prefixColor: String = "§e"
+    ) {
         val msgPrefix = if (prefix) prefixColor + CHAT_PREFIX else ""
-        ChatClickActionManager.oneTimeClick(msgPrefix + message, onClick)
+        ChatClickActionManager.oneTimeClick(msgPrefix + message, onClick, expireAt)
     }
 
     /**
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/DelayedRun.kt b/src/main/java/at/hannibal2/skyhanni/utils/DelayedRun.kt
index 3c6491ac3..0b4c3adc9 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/DelayedRun.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/DelayedRun.kt
@@ -1,5 +1,6 @@
 package at.hannibal2.skyhanni.utils
 
+import at.hannibal2.skyhanni.test.command.ErrorManager
 import at.hannibal2.skyhanni.utils.CollectionUtils.drainTo
 import java.util.concurrent.ConcurrentLinkedQueue
 import kotlin.time.Duration
@@ -22,7 +23,11 @@ object DelayedRun {
         tasks.removeIf { (runnable, time) ->
             val inPast = time.isInPast()
             if (inPast) {
-                runnable()
+                try {
+                    runnable()
+                } catch (e: Exception) {
+                    ErrorManager.logErrorWithData(e, "DelayedRun task crashed while executing")
+                }
             }
             inPast
         }
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt
index 610a0c270..9bc8ff5ae 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/InventoryUtils.kt
@@ -100,5 +100,9 @@ object InventoryUtils {
         }
     }
 
+    fun getItemAtSlotIndex(slotIndex: Int): ItemStack? {
+        return getItemsInOpenChest().find { it.slotIndex == slotIndex }?.stack
+    }
+
     fun NEUInternalName.getAmountInInventory(): Int = countItemsInLowerInventory { it.getInternalNameOrNull() == this }
 }
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
index ca651ea08..9f069f19c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LocationUtils.kt
@@ -95,5 +95,15 @@ object LocationUtils {
     fun AxisAlignedBB.getCenter() = this.getEdgeLengths().multiply(0.5).add(this.minBox())
 
     fun AxisAlignedBB.getTopCenter() = this.getCenter().add(y = (maxY - minY) / 2)
+
+    fun AxisAlignedBB.clampTo(other: AxisAlignedBB): AxisAlignedBB {
+        val minX = max(this.minX, other.minX)
+        val minY = max(this.minY, other.minY)
+        val minZ = max(this.minZ, other.minZ)
+        val maxX = min(this.maxX, other.maxX)
+        val maxY = min(this.maxY, other.maxY)
+        val maxZ = min(this.maxZ, other.maxZ)
+        return AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ)
+    }
 }
 
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
index e8715703f..a03795f59 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/LorenzVec.kt
@@ -18,6 +18,7 @@ import kotlin.math.round
 import kotlin.math.sin
 import kotlin.math.sqrt
 
+
 data class LorenzVec(
     val x: Double,
     val y: Double,
@@ -56,6 +57,17 @@ data class LorenzVec(
         return (dx * dx + dz * dz)
     }
 
+    operator fun plus(other: LorenzVec) = LorenzVec(x + other.x, y + other.y, z + other.z)
+
+    operator fun minus(other: LorenzVec) = LorenzVec(x - other.x, y - other.y, z - other.z)
+
+    operator fun times(other: LorenzVec) = LorenzVec(x * other.x, y * other.y, z * other.z)
+    operator fun times(other: Double) = LorenzVec(x * other, y * other, z * other)
+    operator fun times(other: Int) = LorenzVec(x * other, y * other, z * other)
+
+    operator fun div(other: LorenzVec) = LorenzVec(x / other.x, y / other.y, z / other.z)
+    operator fun div(other: Double) = LorenzVec(x / other, y / other, z / other)
+
     fun add(x: Double = 0.0, y: Double = 0.0, z: Double = 0.0): LorenzVec =
         LorenzVec(this.x + x, this.y + y, this.z + z)
 
@@ -63,17 +75,21 @@ data class LorenzVec(
 
     override fun toString() = "LorenzVec{x=$x, y=$y, z=$z}"
 
+    @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
     fun multiply(d: Double): LorenzVec = LorenzVec(x multiplyZeroSave d, y multiplyZeroSave d, z multiplyZeroSave d)
 
+    @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
     fun multiply(d: Int): LorenzVec =
         LorenzVec(x multiplyZeroSave d.toDouble(), y multiplyZeroSave d.toDouble(), z multiplyZeroSave d.toDouble())
 
+    @Deprecated("Use operator fun div instead", ReplaceWith("this / LorenzVec(x, y, z)"))
     fun divide(d: Double) = multiply(1.0 / d)
 
+    @Deprecated("Use operator fun times instead", ReplaceWith("this * LorenzVec(x, y, z)"))
     fun multiply(v: LorenzVec) = LorenzVec(x multiplyZeroSave v.x, y multiplyZeroSave v.y, z multiplyZeroSave v.z)
 
     fun dotProduct(other: LorenzVec): Double =
-        x multiplyZeroSave other.x + y multiplyZeroSave other.y + z multiplyZeroSave other.z
+        (x multiplyZeroSave other.x) + (y multiplyZeroSave other.y) + (z multiplyZeroSave other.z)
 
     fun angleAsCos(other: LorenzVec) = this.normalize().dotProduct(other.normalize())
 
@@ -81,8 +97,10 @@ data class LorenzVec(
 
     fun angleInDeg(other: LorenzVec) = Math.toDegrees(this.angleInRad(other))
 
+    @Deprecated("Use operator fun plus instead", ReplaceWith("this + other"))
     fun add(other: LorenzVec) = LorenzVec(x + other.x, y + other.y, z + other.z)
 
+    @Deprecated("Use operator fun minus instead", ReplaceWith("this - other"))
     fun subtract(other: LorenzVec) = LorenzVec(x - other.x, y - other.y, z - other.z)
 
     fun normalize() = length().let { LorenzVec(x / it, y / it, z / it) }
@@ -111,7 +129,8 @@ data class LorenzVec(
 
     fun toCleanString(): String = "$x $y $z"
 
-    fun length(): Double = sqrt(x * x + y * y + z * z)
+    fun lengthSquared(): Double = x * x + y * y + z * z
+    fun length(): Double = sqrt(this.lengthSquared())
 
     fun isZero(): Boolean = x == 0.0 && y == 0.0 && z == 0.0
 
@@ -183,6 +202,24 @@ data class LorenzVec(
     fun rotateXZ(theta: Double) = LorenzVec(x * cos(theta) + z * sin(theta), y, -x * sin(theta) + z * cos(theta))
     fun rotateYZ(theta: Double) = LorenzVec(x, y * cos(theta) - z * sin(theta), y * sin(theta) + z * cos(theta))
 
+    fun nearestPointOnLine(startPos: LorenzVec, endPos: LorenzVec): LorenzVec {
+        var d = endPos - startPos
+        val w = this - startPos
+
+        val dp = d.lengthSquared()
+        var dt = 0.0
+
+        if (dp != dt) dt = (w.dotProduct(d) / dp).coerceIn(0.0, 1.0)
+
+        d *= dt
+        d += startPos
+        return d
+    }
+
+    fun distanceToLine(startPos: LorenzVec, endPos: LorenzVec): Double {
+        return (nearestPointOnLine(startPos, endPos) - this).lengthSquared()
+    }
+
     companion object {
 
         fun getFromYawPitch(yaw: Double, pitch: Double): LorenzVec {
@@ -231,3 +268,5 @@ fun Array<Double>.toLorenzVec(): LorenzVec {
 fun RenderUtils.translate(vec: LorenzVec) = GlStateManager.translate(vec.x, vec.y, vec.z)
 
 fun AxisAlignedBB.expand(vec: LorenzVec) = this.expand(vec.x, vec.y, vec.z)
+
+fun AxisAlignedBB.expand(amount: Double) = this.expand(amount, amount, amount)
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt b/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt
index c6ebdd836..4022b382c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/MinecraftConsoleFilter.kt
@@ -35,6 +35,9 @@ class MinecraftConsoleFilter(private val loggerConfigName: String) : Filter {
         }
     }
 
+    // prevents error sending on every shutdown
+    fun stop() {}
+
     override fun filter(event: LogEvent?): Filter.Result {
         if (event == null) return Filter.Result.ACCEPT
 
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/Season.kt b/src/main/java/at/hannibal2/skyhanni/utils/Season.kt
deleted file mode 100644
index 33dd9a221..000000000
--- a/src/main/java/at/hannibal2/skyhanni/utils/Season.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package at.hannibal2.skyhanni.utils
-
-import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
-import at.hannibal2.skyhanni.utils.UtilsPatterns.seasonPattern
-import io.github.moulberry.notenoughupdates.util.SkyBlockTime
-
-enum class Season(
-    val season: String,
-    val abbreviatedPerk: String,
-    val perk: String,
-) {
-
-    SPRING("§dSpring", "§6+25☘", "§7Gain §6+25☘ Farming Fortune§7."),
-    SUMMER("§6Summer", "§3+20☯", "§7Gain §3+20☯ Farming Wisdom§7."),
-    AUTUMN("§eAutumn", "§a15%+§4ൠ", "§4Pests §7spawn §a15% §7more often."),
-    WINTER("§9Winter", "§a5%+§cC", "§7Visitors give §a5% §7more §cCopper."),
-    ;
-
-    fun getPerk(abbreviate: Boolean): String = if (abbreviate) abbreviatedPerk else perk
-    fun getSeason(abbreviate: Boolean): String = if (abbreviate) season.take(4) else season
-
-    companion object {
-
-        fun getCurrentSeason(): Season? = getSeasonByName(SkyBlockTime.now().monthName)
-
-        private fun getSeasonByName(name: String): Season? =
-            seasonPattern.matchMatcher(name) { entries.find { it.season.endsWith(group("season")) } }
-    }
-}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/SkyblockSeason.kt b/src/main/java/at/hannibal2/skyhanni/utils/SkyblockSeason.kt
new file mode 100644
index 000000000..4e0409465
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/SkyblockSeason.kt
@@ -0,0 +1,29 @@
+package at.hannibal2.skyhanni.utils
+
+import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher
+import at.hannibal2.skyhanni.utils.UtilsPatterns.seasonPattern
+import io.github.moulberry.notenoughupdates.util.SkyBlockTime
+
+enum class SkyblockSeason(
+    val season: String,
+    val abbreviatedPerk: String,
+    val perk: String,
+) {
+
+    SPRING("§dSpring", "§6+25☘", "§7Gain §6+25☘ Farming Fortune§7."),
+    SUMMER("§6Summer", "§3+20☯", "§7Gain §3+20☯ Farming Wisdom§7."),
+    AUTUMN("§eAutumn", "§a15%+§4ൠ", "§4Pests §7spawn §a15% §7more often."),
+    WINTER("§9Winter", "§a5%+§cC", "§7Visitors give §a5% §7more §cCopper."),
+    ;
+
+    fun getPerk(abbreviate: Boolean): String = if (abbreviate) abbreviatedPerk else perk
+    fun getSeason(abbreviate: Boolean): String = if (abbreviate) season.take(4) else season
+
+    companion object {
+
+        fun getCurrentSeason(): SkyblockSeason? = getSeasonByName(SkyBlockTime.now().monthName)
+
+        private fun getSeasonByName(name: String): SkyblockSeason? =
+            seasonPattern.matchMatcher(name) { entries.find { it.season.endsWith(group("season")) } }
+    }
+}
-- 
cgit