diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java index 667e3233109d..bb7ea595b94d 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/laneswitch/FarmingLaneConfig.java @@ -2,13 +2,18 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.garden.CropType; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorInfoText; import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import java.util.ArrayList; +import java.util.List; + public class FarmingLaneConfig { @Expose @@ -37,4 +42,11 @@ public class FarmingLaneConfig { @FeatureToggle public boolean cornerWaypoints = false; + @Expose + @ConfigOption( + name = "Ignored Crops", + desc = "Add the crops you wish to not setup a lane for." + ) + @ConfigEditorDraggableList() + public List ignoredCrops = new ArrayList<>(); } diff --git a/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt b/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt index 92a36b62363d..d38b6824b864 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/EntityMovementData.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.events.EntityMoveEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWarpEvent @@ -8,22 +9,36 @@ import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.getLorenzVec import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft import net.minecraft.entity.Entity import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @SkyHanniModule object EntityMovementData { private val warpingPattern by RepoPattern.pattern( "data.entity.warping", - "§7(?:Warping|Warping you to your SkyBlock island|Warping using transfer token|Finding player|Sending a visit request)\\.\\.\\." + "§7(?:Warping|Warping you to your SkyBlock island|Warping using transfer token|Finding player|Sending a visit request)\\.\\.\\.", ) + private var nextTeleport: OnNextTeleport? = null + + fun onNextTeleport(island: IslandType, action: () -> Unit) { + nextTeleport = OnNextTeleport(island, action) + } + + class OnNextTeleport(val island: IslandType, val action: () -> Unit) { + val startTime: SimpleTimeMark = SimpleTimeMark.now() + } + private val entityLocation = mutableMapOf() fun addToTrack(entity: Entity) { @@ -32,6 +47,40 @@ object EntityMovementData { } } + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + val nextData = nextTeleport ?: return + if (nextData.island != event.newIsland) return + val passedSince = nextData.startTime.passedSince() + if (passedSince > 5.seconds) { + nextTeleport = null + return + } + + DelayedRun.runDelayed(100.milliseconds) { + nextData.action() + } + nextTeleport = null + } + + @SubscribeEvent + fun onPlayerMove(event: EntityMoveEvent) { + if (!LorenzUtils.inSkyBlock || event.entity != Minecraft.getMinecraft().thePlayer) return + + val nextData = nextTeleport ?: return + + val passedSince = nextData.startTime.passedSince() + if (passedSince > 5.seconds) { + nextTeleport = null + return + } + if (passedSince > 50.milliseconds && nextData.island.isInIsland()) { + nextData.action() + nextTeleport = null + return + } + } + @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!LorenzUtils.inSkyBlock) return diff --git a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt index 73915c22d183..9829b4ec9e92 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt @@ -19,7 +19,6 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.sorted import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.GraphUtils import at.hannibal2.skyhanni.utils.LocationUtils -import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor @@ -39,7 +38,6 @@ import net.minecraft.client.Minecraft import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.awt.Color import java.io.File -import kotlin.math.abs import kotlin.time.Duration.Companion.milliseconds /** @@ -104,18 +102,17 @@ object IslandGraphs { val existsForThisIsland get() = currentIslandGraph != null - var closedNote: GraphNode? = null - var secondClosedNote: GraphNode? = null + private var pathfindClosestNode: GraphNode? = null + var closestNode: GraphNode? = null + private var secondClosestNode: GraphNode? = null private var currentTarget: LorenzVec? = null private var currentTargetNode: GraphNode? = null private var label = "" - private var distanceViaNodes = 0.0 - private var distanceToNextNode = 0.0 + private var lastDistance = 0.0 private var totalDistance = 0.0 private var color = Color.WHITE private var shouldAllowRerouting = false - private var showGoalExact = false private var onFound: () -> Unit = {} private var goal: GraphNode? = null set(value) { @@ -215,7 +212,7 @@ object IslandGraphs { // calling various update functions to make swtiching between deep caverns and glacite tunnels bareable handleTick() - IslandAreas.noteMoved() + IslandAreas.nodeMoved() DelayedRun.runDelayed(150.milliseconds) { IslandAreas.updatePosition() } @@ -223,20 +220,21 @@ object IslandGraphs { private fun reset() { stop() - closedNote = null + pathfindClosestNode = null + closestNode = null } @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!LorenzUtils.inSkyBlock) return - handleTick() if (event.isMod(2)) { + handleTick() checkMoved() } } private fun handleTick() { - val prevClosed = closedNote + val prevClosest = pathfindClosestNode currentTarget?.let { if (it.distanceToPlayer() < 3) { @@ -252,39 +250,46 @@ object IslandGraphs { val graph = currentIslandGraph ?: return val sortedNodes = graph.sortedBy { it.position.distanceSqToPlayer() } val newClosest = sortedNodes.first() - if (closedNote == newClosest) return - if (onCurrentPath()) return - - closedNote = newClosest - secondClosedNote = sortedNodes.getOrNull(1) - onNewNote() - hasMoved = false - if (newClosest == prevClosed) return - findNewPath() + if (pathfindClosestNode == newClosest) return + val newPath = !onCurrentPath() + + closestNode = newClosest + secondClosestNode = sortedNodes.getOrNull(1) + onNewNode() + if (newClosest == prevClosest) return + if (newPath) { + pathfindClosestNode = closestNode + findNewPath() + } } private fun onCurrentPath(): Boolean { val path = fastestPath ?: return false val closest = path.nodes.minBy { it.position.distanceSqToPlayer() } val distance = closest.position.distanceToPlayer() - if (distance > 5) return false - - if (distance < 3) { - val index = path.nodes.indexOf(closest) - val newNodes = path.drop(index) - val newGraph = Graph(newNodes) - fastestPath = newGraph - newNodes.getOrNull(1)?.let { - secondClosedNote = it - } - setFastestPath(newGraph to newGraph.totalLenght(), setPath = false) + if (distance > 7) return false + + val index = path.nodes.indexOf(closest) + val newNodes = path.drop(index) + val newGraph = Graph(newNodes) + fastestPath = skipIfCloser(newGraph) + newNodes.getOrNull(1)?.let { + secondClosestNode = it } + setFastestPath(newGraph to newGraph.totalLenght(), setPath = false) return true } + private fun skipIfCloser(graph: Graph): Graph = if (graph.nodes.size > 1) { + val hideNearby = if (Minecraft.getMinecraft().thePlayer.onGround) 3 else 5 + Graph(graph.nodes.takeLastWhile { it.position.distanceToPlayer() > hideNearby }) + } else { + graph + } + private fun findNewPath() { val goal = IslandGraphs.goal ?: return - val closest = closedNote ?: return + val closest = pathfindClosestNode ?: return val (path, distance) = GraphUtils.findShortestPathAsGraphWithDistance(closest, goal) val first = path.firstOrNull() @@ -307,8 +312,6 @@ object IslandGraphs { private fun Graph.totalLenght(): Double = nodes.zipWithNext().sumOf { (a, b) -> a.position.distance(b.position) } private fun handlePositionChange() { - val secondClosestNode = secondClosedNote ?: return - distanceToNextNode = secondClosestNode.position.distanceToPlayer() updateChat() } @@ -331,25 +334,21 @@ object IslandGraphs { } private fun setFastestPath(path: Pair, setPath: Boolean = true) { + // TODO cleanup val (fastestPath, distance) = path.takeIf { it.first.isNotEmpty() } ?: return val nodes = fastestPath.nodes.toMutableList() if (Minecraft.getMinecraft().thePlayer.onGround) { nodes.add(0, GraphNode(0, LocationUtils.playerLocation())) } if (setPath) { - this.fastestPath = Graph(cutByMaxDistance(nodes, 3.0)) + this.fastestPath = skipIfCloser(Graph(cutByMaxDistance(nodes, 2.0))) } - - val diff = fastestPath.getOrNull(1)?.let { - fastestPath.first().position.distance(it.position) - } ?: 0.0 - this.distanceViaNodes = distance - diff updateChat() } - private fun onNewNote() { + private fun onNewNode() { // TODO create an event - IslandAreas.noteMoved() + IslandAreas.nodeMoved() if (shouldAllowRerouting) { tryRerouting() } @@ -357,12 +356,12 @@ object IslandGraphs { private fun tryRerouting() { val target = currentTargetNode ?: return - val closest = closedNote ?: return + val closest = pathfindClosestNode ?: return val map = GraphUtils.findAllShortestDistances(closest).distances.filter { it.key.sameNameAndTags(target) } val newTarget = map.sorted().keys.firstOrNull() ?: return if (newTarget != target) { ChatUtils.debug("Rerouting navigation..") - newTarget.pathFind(label, color, onFound, allowRerouting = true, condition) + newTarget.pathFind(label, color, onFound, allowRerouting = true, condition = condition) } } @@ -372,9 +371,8 @@ object IslandGraphs { fastestPath = null currentTargetNode = null label = "" - distanceToNextNode = 0.0 - distanceViaNodes = 0.0 totalDistance = 0.0 + lastDistance = 0.0 } /** @@ -396,7 +394,7 @@ object IslandGraphs { reset() currentTargetNode = this shouldAllowRerouting = allowRerouting - pathFind0(location = position, label, color, onFound, showGoalExact = false, condition) + pathFind0(location = position, label, color, onFound, condition) } /** @@ -406,7 +404,6 @@ object IslandGraphs { * @param label The name of the naviation goal in chat. * @param color The color of the lines in world. * @param onFound The callback that gets fired when the goal is reached. - * @param showGoalExact Wether the exact location should be shown as a waypoint, as well as shwoing a line from last node to the goal location. * @param condition The pathfinding stops when the condition is no longer valid. */ fun pathFind( @@ -414,12 +411,11 @@ object IslandGraphs { label: String, color: Color = LorenzColor.WHITE.toColor(), onFound: () -> Unit = {}, - showGoalExact: Boolean = false, condition: () -> Boolean, ) { reset() shouldAllowRerouting = false - pathFind0(location, label, color, onFound, showGoalExact, condition) + pathFind0(location, label, color, onFound, condition) } private fun pathFind0( @@ -427,14 +423,12 @@ object IslandGraphs { label: String, color: Color = LorenzColor.WHITE.toColor(), onFound: () -> Unit = {}, - showGoalExact: Boolean = false, condition: () -> Boolean, ) { currentTarget = location this.label = label this.color = color this.onFound = onFound - this.showGoalExact = showGoalExact this.condition = condition val graph = currentIslandGraph ?: return goal = graph.minBy { it.position.distance(currentTarget!!) } @@ -445,9 +439,18 @@ object IslandGraphs { private fun updateChat() { if (label == "") return - val finalDistance = distanceViaNodes + distanceToNextNode - if (finalDistance == 0.0) return - val distance = finalDistance.roundTo(1) + val path = fastestPath ?: return + var distance = 0.0 + for ((a, b) in path.zipWithNext()) { + distance += a.position.distance(b.position) + } + val distanceToPlayer = path.first().position.distanceToPlayer() + distance += distanceToPlayer + distance = distance.roundTo(1) + + if (distance == lastDistance) return + lastDistance = distance + if (distance == 0.0) return if (totalDistance == 0.0 || distance > totalDistance) { totalDistance = distance } @@ -470,29 +473,25 @@ object IslandGraphs { @SubscribeEvent fun onRenderWorld(event: LorenzRenderWorldEvent) { if (!LorenzUtils.inSkyBlock) return - var path = fastestPath ?: return - - if (path.nodes.size > 1) { - val hideNearby = if (Minecraft.getMinecraft().thePlayer.onGround) 5 else 7 - path = Graph(path.nodes.takeLastWhile { it.position.distanceToPlayer() > hideNearby }) - } -// graph = skipNodes(graph) ?: graph + val path = fastestPath ?: return + // maybe reuse for debuggin +// for ((a, b) in path.nodes.zipWithNext()) { +// val diff = a.position.distance(b.position) +// event.drawString(a.position, "diff: ${diff.roundTo(1)}") +// } event.draw3DPathWithWaypoint( path, color, 6, true, - bezierPoint = 2.0, + bezierPoint = 0.6, textSize = 1.0, - markLastBlock = showGoalExact, ) - if (showGoalExact) { - val targetLocation = currentTarget ?: return - val lastNode = path.nodes.last().position - event.draw3DLine(lastNode.add(0.5, 0.5, 0.5), targetLocation.add(0.5, 0.5, 0.5), color, 4, true) - } + val targetLocation = currentTarget ?: return + val lastNode = path.nodes.lastOrNull()?.position ?: return + event.draw3DLine(lastNode.add(0.5, 0.5, 0.5), targetLocation.add(0.5, 0.5, 0.5), color, 4, true) } // TODO move into new utils class @@ -524,47 +523,4 @@ object IslandGraphs { return locations.map { GraphNode(index++, it) } } - - // trying to find a faster node-path, if the future nodes are in line of sight and gratly beneift the current path - private fun skipNodes(graph: Graph): Graph? { - val closedNode = closedNote ?: return null - - val playerEyeLocation = LocationUtils.playerEyeLocation() - val playerY = playerEyeLocation.y - 1 - - val distanceToPlayer = closedNode.position.distanceToPlayer() - val skipNodeDistance = distanceToPlayer > 8 - val maxSkipDistance = if (skipNodeDistance) 50.0 else 20.0 - - val nodes = graph.nodes - val potentialSkip = - nodes.lastOrNull { it.position.canBeSeen(maxSkipDistance, -1.0) && abs(it.position.y - playerY) <= 2 } ?: return null - - val angleSkip = if (potentialSkip == nodes.first()) { - false - } else { - val v1 = potentialSkip.position - playerEyeLocation - val v2 = nodes.first().position - playerEyeLocation - val v = v1.angleInRad(v2) - v > 1 - } - - if (!skipNodeDistance && !angleSkip) return null - - val list = mutableListOf() - list.add(potentialSkip) - - var passed = false - for (node in nodes) { - if (passed) { - list.add(node) - } else { - if (node == potentialSkip) { - passed = true - } - } - } - - return Graph(list) - } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt b/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt index 2acbe3546117..eed2d5e70dba 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt @@ -58,26 +58,28 @@ object IslandExceptions { armorStand: EntityArmorStand?, nextEntity: EntityLivingBase?, ) = when { - baseEntity is EntityZombie && armorStand != null && + baseEntity is EntityZombie && + armorStand != null && (armorStand.name == "§e﴾ §c§lThe Watcher§r§r §e﴿" || armorStand.name == "§3§lWatchful Eye§r") -> MobData.MobResult.found( MobFactories.special(baseEntity, armorStand.cleanName(), armorStand), ) - baseEntity is EntityCaveSpider -> MobUtils.getClosedArmorStand(baseEntity, 2.0).takeNonDefault() + baseEntity is EntityCaveSpider -> MobUtils.getClosestArmorStand(baseEntity, 2.0).takeNonDefault() .makeMobResult { MobFactories.dungeon(baseEntity, it) } baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && baseEntity.name == "Shadow Assassin" -> - MobUtils.getClosedArmorStandWithName(baseEntity, 3.0, "Shadow Assassin") + MobUtils.getClosestArmorStandWithName(baseEntity, 3.0, "Shadow Assassin") .makeMobResult { MobFactories.dungeon(baseEntity, it) } baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && baseEntity.name == "The Professor" -> MobUtils.getArmorStand(baseEntity, 9) .makeMobResult { MobFactories.boss(baseEntity, it) } - baseEntity is EntityOtherPlayerMP && baseEntity.isNPC() && + baseEntity is EntityOtherPlayerMP && + baseEntity.isNPC() && (nextEntity is EntityGiantZombie || nextEntity == null) && - baseEntity.name.contains("Livid") -> MobUtils.getClosedArmorStandWithName(baseEntity, 6.0, "﴾ Livid") + baseEntity.name.contains("Livid") -> MobUtils.getClosestArmorStandWithName(baseEntity, 6.0, "﴾ Livid") .makeMobResult { MobFactories.boss(baseEntity, it, overriddenName = "Real Livid") } baseEntity is EntityIronGolem && MobFilter.wokeSleepingGolemPattern.matches(armorStand?.name ?: "") -> @@ -174,7 +176,8 @@ object IslandExceptions { baseEntity: EntityLivingBase, armorStand: EntityArmorStand?, ) = when { - baseEntity is EntityMagmaCube && armorStand != null && + baseEntity is EntityMagmaCube && + armorStand != null && armorStand.cleanName() == "[Lv100] Bal ???❤" -> MobData.MobResult.found( Mob(baseEntity, Mob.Type.BOSS, armorStand, "Bal", levelOrTier = 100), @@ -188,7 +191,8 @@ object IslandExceptions { armorStand: EntityArmorStand?, nextEntity: EntityLivingBase?, ) = when { - baseEntity is EntityOcelot && armorStand?.isDefaultValue() == false && + baseEntity is EntityOcelot && + armorStand?.isDefaultValue() == false && armorStand.name.startsWith("§8[§7Lv155§8] §cAzrael§r") -> MobUtils.getArmorStand(baseEntity, 1) .makeMobResult { MobFactories.basic(baseEntity, it) } @@ -203,7 +207,8 @@ object IslandExceptions { MobUtils.getArmorStand(baseEntity, 2) .makeMobResult { MobFactories.basic(baseEntity, it, listOf(armorStand)) } - baseEntity is EntityZombie && armorStand?.isDefaultValue() == true && + baseEntity is EntityZombie && + armorStand?.isDefaultValue() == true && MobUtils.getNextEntity(baseEntity, 4)?.name?.startsWith("§e") == true -> petCareHandler(baseEntity) @@ -250,7 +255,8 @@ object IslandExceptions { .take(RAT_SEARCH_UP_TO - RAT_SEARCH_START + 1) .map { i -> MobUtils.getArmorStand(baseEntity, i) } .firstOrNull { - it != null && it.distanceTo(baseEntity) < 4.0 && + it != null && + it.distanceTo(baseEntity) < 4.0 && it.inventory?.get(4)?.getSkullTexture() == MobFilter.RAT_SKULL }?.let { MobData.MobResult.found(Mob(baseEntity, mobType = Mob.Type.BASIC, armorStand = it, name = "Rat")) diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt index e6ebadab8e5a..624a2d0c2b95 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/PowderMiningChatFilter.kt @@ -33,6 +33,7 @@ object PowderMiningChatFilter { val patternGroup = RepoPattern.group("filter.powdermining") + // TODO rename to "openedRewards" ? private var unclosedRewards = false /** diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt index ee2a9028ae7e..2257772c8f3c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalQuickStart.kt @@ -32,6 +32,7 @@ object CarnivalQuickStart { private val cowboy by repoGroup.pattern("cowboy", "Carnival Cowboy") private var lastChat = SimpleTimeMark.farPast() + private var lastClicked = SimpleTimeMark.farPast() @SubscribeEvent fun onEntityClick(event: EntityClickEvent) { @@ -44,6 +45,8 @@ object CarnivalQuickStart { pirate.matches(mob.name) -> "carnival_pirateman" else -> return } + if (lastClicked.passedSince() < 1.seconds) return + lastClicked = SimpleTimeMark.now() HypixelCommands.npcOption(type, "r_2_1") event.cancel() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalReminder.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalReminder.kt index eff7516617b1..d77861872d6d 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalReminder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalReminder.kt @@ -1,6 +1,9 @@ package at.hannibal2.skyhanni.features.event.carnival import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.EntityMovementData +import at.hannibal2.skyhanni.data.IslandGraphs +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.Perk import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.LorenzChatEvent @@ -11,6 +14,7 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow @@ -90,6 +94,9 @@ object CarnivalReminder { "warp to The Carnival", ) { HypixelCommands.warp("carnival") + EntityMovementData.onNextTeleport(IslandType.HUB) { + IslandGraphs.pathFind(LorenzVec(-89.5, 71.0, -18.7), "§aCarnival Tickets", condition = { config.reminderDailyTickets }) + } } nextCheckTime = 5.0.minutes.fromNow() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityNpc.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityNpc.kt index c105a0abf227..0546e5ff98d2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityNpc.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityNpc.kt @@ -1,5 +1,8 @@ package at.hannibal2.skyhanni.features.event.hoppity +import at.hannibal2.skyhanni.data.EntityMovementData +import at.hannibal2.skyhanni.data.IslandGraphs +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent @@ -15,6 +18,7 @@ import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RenderUtils.highlight import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SkyBlockTime @@ -60,7 +64,12 @@ object HoppityNpc { actionName = "warp to hub", action = { HypixelCommands.warp("hub") - // afterNextIslandwarpTtp hub: IslandGraphs.pathFind(hoppity) + EntityMovementData.onNextTeleport(IslandType.HUB) { + IslandGraphs.pathFind( + LorenzVec(6.4, 70.0, 7.4), + "§aHoppity's Shop", + condition = { config.hoppityShopReminder }) + } }, ) diff --git a/src/main/java/at/hannibal2/skyhanni/features/fame/CityProjectFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/fame/CityProjectFeatures.kt index 5a1e1361a784..cf5d3ce5a5a2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fame/CityProjectFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fame/CityProjectFeatures.kt @@ -2,6 +2,9 @@ package at.hannibal2.skyhanni.features.fame import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator +import at.hannibal2.skyhanni.data.EntityMovementData +import at.hannibal2.skyhanni.data.IslandGraphs +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.GuiRenderEvent @@ -20,6 +23,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getItemStack @@ -79,7 +83,16 @@ object CityProjectFeatures { "Daily City Project Reminder!", config::dailyReminder, actionName = "warp to Hub", - action = { HypixelCommands.warp("hub") }, + action = { + HypixelCommands.warp("hub") + EntityMovementData.onNextTeleport(IslandType.HUB) { + IslandGraphs.pathFind( + LorenzVec(9.3, 72.0, -103.4), + "§aCity Project", + condition = { config.dailyReminder }, + ) + } + }, ) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fame/UpgradeReminder.kt b/src/main/java/at/hannibal2/skyhanni/features/fame/UpgradeReminder.kt index d5f33204ce25..d22151c1b014 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fame/UpgradeReminder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fame/UpgradeReminder.kt @@ -2,6 +2,9 @@ package at.hannibal2.skyhanni.features.fame import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator +import at.hannibal2.skyhanni.data.EntityMovementData +import at.hannibal2.skyhanni.data.IslandGraphs +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent @@ -13,6 +16,7 @@ import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher @@ -162,7 +166,16 @@ object UpgradeReminder { "The §a$name §eupgrade has completed!", config::accountUpgradeReminder, actionName = "warp to Hub", - action = { HypixelCommands.warp("hub") }, + action = { + HypixelCommands.warp("hub") + EntityMovementData.onNextTeleport(IslandType.HUB) { + IslandGraphs.pathFind( + LorenzVec(-2.6, 73.0, -101.6), + "§eCommunity Shop", + condition = { config.accountUpgradeReminder }, + ) + } + }, ) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt index 22e9c12f7990..d7452725fd05 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt @@ -639,20 +639,20 @@ object ComposterOverlay { add("currentOrganicMatterItem: $currentOrganicMatterItem") add("currentFuelItem: $currentFuelItem") - println(" ") + add(" ") val composterUpgrades = ComposterAPI.composterUpgrades if (composterUpgrades == null) { - println("composterUpgrades is null") + add("composterUpgrades is null") } else { for ((a, b) in composterUpgrades) { - println("upgrade $a: $b") + add("upgrade $a: $b") } } - println(" ") + add(" ") val tabListData = ComposterAPI.tabListData for ((a, b) in tabListData) { - println("tabListData $a: $b") + add("tabListData $a: $b") } } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneAPI.kt index ba0eaee5dd4e..b9b091e53a27 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneAPI.kt @@ -43,6 +43,7 @@ object FarmingLaneAPI { private fun warnNoLane(crop: CropType?) { if (crop == null || currentLane != null) return + if (crop in config.ignoredCrops) return if (!GardenAPI.hasFarmingToolInHand()) return if (FarmingLaneCreator.detection) return if (!config.distanceDisplay && !config.laneSwitchNotification.enabled) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt index 25abb16ed82f..9fcbbad0be11 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt @@ -69,7 +69,7 @@ object ExperimentationTableAPI { */ val rewardPattern by patternGroup.pattern( "rewards", - "\\d{1,3}k Enchanting Exp|Enchanted Book|(?:Titanic |Grand |\\b)Experience Bottle|Metaphysical Serum|Experiment The Fish", + "\\d{1,3}k Enchanting Exp|Enchanted Book|(?:Titanic |Grand |\\b)Experience Bottle|Metaphysical Serum|Experiment the Fish", ) /** @@ -131,6 +131,14 @@ object ExperimentationTableAPI { "(?:COLOSSAL_|TITANIC_|GRAND_|\\b)EXP_BOTTLE", ) + /** + * REGEX-TEST: Remaining Clicks: 22 + */ + val remainingClicksPattern by patternGroup.pattern( + "clicks", + "Remaining Clicks: (?\\d+)" + ) + /** * REGEX-TEST: ☕ You renewed the experiment table! (1/3) */ diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairDataDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairDataDisplay.kt new file mode 100644 index 000000000000..627974e6baac --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairDataDisplay.kt @@ -0,0 +1,291 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.GuiContainerEvent.SlotClickEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.remainingClicksPattern +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.CollectionUtils.equalsOneOf +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils.isAnyOf +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds + +// TODO important: all use cases of listOf in combination with string needs to be gone. no caching, constant new list creation, and bad design. +@SkyHanniModule +object SuperpairDataDisplay { + + private val config get() = SkyHanniMod.feature.inventory.experimentationTable + + private data class SuperpairItem(val index: Int, val reward: String, val damage: Int) + private data class FoundData(val item: SuperpairItem? = null, val first: SuperpairItem? = null, val second: SuperpairItem? = null) + + private enum class FoundType { + NORMAL, + POWERUP, + MATCH, + PAIR + } + + private val sideSpaces1 = listOf(17, 18, 26, 27, 35, 36) + private val sideSpaces2 = listOf(16, 17, 18, 19, 25, 26, 27, 28, 34, 35, 36, 37) + private val emptySuperpairItem = SuperpairItem(-1, "", -1) + + private var display = emptyList() + private var uncoveredItems = mutableMapOf() + private var found = mutableMapOf>() + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + display = emptyList() + + uncoveredItems = mutableMapOf() + found.clear() + } + + @SubscribeEvent + fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { + if (!isEnabled()) return + if (display.isEmpty()) display = drawDisplay() + + config.superpairDisplayPosition.renderStrings(display, posLabel = "Superpair Experiment Information") + } + + @SubscribeEvent + fun onSlotClick(event: SlotClickEvent) { + if (!isEnabled()) return + val currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return + + val item = event.item ?: return + if (isOutOfBounds(event.slotId, currentExperiment) || item.displayName.removeColor() == "?") return + + val clicksItem = InventoryUtils.getItemAtSlotIndex(4) + + // TODO add variable name to indicate what is going on here + if (uncoveredItems.none { it.value.index == event.slotId && it.key == uncoveredItems.keys.max() }) { + if (clicksItem != null) { + remainingClicksPattern.matchMatcher(clicksItem.displayName.removeColor()) { if (group("clicks").toInt() == 0) return } + } + + handleItem(event.slotId) + } + } + + private fun handleItem(slot: Int) = DelayedRun.runDelayed(200.milliseconds) { + val itemNow = InventoryUtils.getItemAtSlotIndex(slot) ?: return@runDelayed + val itemName = itemNow.displayName.removeColor() + val reward = convertToReward(itemNow) + val itemData = SuperpairItem(slot, reward, itemNow.itemDamage) + val uncovered = uncoveredItems.keys.maxOrNull() ?: -1 + + if (isWaiting(itemName)) return@runDelayed + + if (uncoveredItems.none { it.key == uncovered && it.value.index == slot }) uncoveredItems[uncovered + 1] = itemData + + when { + isPowerUp(reward) -> handlePowerUp(itemData, uncovered + 1) + isReward(itemName) -> handleReward(itemData, uncovered + 1) + } + + val since = clicksSinceSeparator(uncoveredItems) + + val lastReward = uncoveredItems.entries.last().value.reward + // TODO use repo patterns for "Instant Find" + if ((since >= 2 || (since == -1 && uncoveredItems.size >= 2)) && lastReward != "Instant Find") uncoveredItems[uncovered + 2] = + emptySuperpairItem + + display = drawDisplay() + } + + private fun handlePowerUp(item: SuperpairItem, uncovered: Int) { + // TODO use repo patterns for "Instant Find" + if (item.reward != "Instant Find") uncoveredItems.remove(uncovered) + + val itemData = FoundData(item = item) + found.getOrPut(FoundType.POWERUP) { mutableListOf(itemData) }.apply { if (!contains(itemData)) add(itemData) } + } + + private fun handleReward(item: SuperpairItem, uncovered: Int) { + val last = uncoveredItems.getOrDefault(uncovered - 1, item) + + if (isWaiting(last.reward)) return + + when { + // TODO use repo patterns for "Instant Find" + last.reward == "Instant Find" -> handleInstantFind(item, uncovered) + hasFoundPair(item, last) -> handleFoundPair(item, last) + hasFoundMatch(item) -> handleFoundMatch(item) + else -> handleNormalReward(item) + } + + println(found) + } + + private fun handleInstantFind(item: SuperpairItem, uncovered: Int) { + uncoveredItems[uncovered - 1] = item + uncoveredItems[uncovered] = emptySuperpairItem + + handleFoundPair(item, emptySuperpairItem) + } + + private fun handleFoundPair( + first: SuperpairItem, + second: SuperpairItem, + ) { + found.entries.forEach { + when (it.key) { + FoundType.MATCH -> it.value.removeIf { data -> data.first?.sameAs(first) ?: false || data.second?.sameAs(first) ?: false } + FoundType.NORMAL -> it.value.removeIf { data -> data.item?.sameAs(first) ?: false || data.item?.sameAs(second) ?: false } + else -> {} + } + } + + val pairData = FoundData(first = first, second = second) + + found.getOrPut(FoundType.PAIR) { mutableListOf(pairData) }.apply { if (!contains(pairData)) add(pairData) } + } + + private fun handleFoundMatch(item: SuperpairItem) { + // TODO better name + val match = uncoveredItems.values.find { it.index != item.index && it.sameAs(item) } ?: return + + found.entries.forEach { + when { + it.key.isAnyOf(FoundType.MATCH, FoundType.PAIR) -> { + // TODO extract logic in some way + if (it.value.any { data -> + (data.first?.index ?: -1).equalsOneOf(item.index, match.index) || + (data.second?.index + ?: -1).equalsOneOf(item.index, match.index) + }) { + return + } + } + + it.key == FoundType.NORMAL -> it.value.removeIf { data -> + (data.item?.index ?: -1).equalsOneOf(item.index, match.index) + } + + else -> {} + } + } + + val pairData = FoundData(first = item, second = match) + found.getOrPut(FoundType.MATCH) { mutableListOf(pairData) }.apply { if (!contains(pairData)) add(pairData) } + } + + private fun handleNormalReward(item: SuperpairItem) { + for ((key, value) in found.entries) { + when { + key.isAnyOf(FoundType.MATCH, FoundType.PAIR) -> { + if (value.any { data -> + item.index.equalsOneOf(data.first?.index ?: -1, data.second?.index ?: -1) + }) return + } + + else -> if (value.any { data -> + (data.item?.index ?: -1) == item.index && data.item?.sameAs(item) == true + }) return + } + } + + val itemData = FoundData(item = item) + found.getOrPut(FoundType.NORMAL) { mutableListOf(itemData) }.apply { if (!contains(itemData)) add(itemData) } + } + + private fun drawDisplay() = buildList { + val currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return emptyList() + + add("§6Superpair Experimentation Data") + add("") + + val normals = found.entries.firstOrNull { it.key == FoundType.NORMAL }?.value ?: mutableListOf() + val powerups = found.entries.firstOrNull { it.key == FoundType.POWERUP }?.value ?: mutableListOf() + val matches = found.entries.firstOrNull { it.key == FoundType.MATCH }?.value ?: mutableListOf() + val pairs = found.entries.firstOrNull { it.key == FoundType.PAIR }?.value ?: mutableListOf() + val possiblePairs = calculatePossiblePairs(currentExperiment) + + if (pairs.isNotEmpty()) add("§2Found") + for (pair in pairs) { + val prefix = determinePrefix(pairs.indexOf(pair), pairs.lastIndex) + add(" $prefix §a${pair.first?.reward ?: ""}") + } + if (matches.isNotEmpty()) add("§eMatched") + for (match in matches) { + val prefix = determinePrefix(matches.indexOf(match), matches.lastIndex) + add(" $prefix §e${match.first?.reward ?: ""}") + } + if (powerups.isNotEmpty()) add("§bPowerUp") + for (powerup in powerups) { + val prefix = determinePrefix(powerups.indexOf(powerup), powerups.size - 1) + add(" $prefix §b${powerup.item?.reward ?: ""}") + } + val toAdd = mutableListOf() + if (possiblePairs >= 1) toAdd.add("§ePairs - $possiblePairs") + if (2 - powerups.size >= 1) toAdd.add("§bPowerUps - ${2 - powerups.size}") + if (normals.isNotEmpty()) toAdd.add("§7Normals - ${normals.size}") + + if (toAdd.isNotEmpty()) { + add("") + add("§4Not found") + } + for (string in toAdd) if (string != toAdd.last()) add(" ├ $string") else add(" └ $string") + } + + private fun calculatePossiblePairs(currentExperiment: Experiment) = + ((currentExperiment.gridSize - 2) / 2) - found.filter { it.key != FoundType.POWERUP }.values.sumOf { it.size } + + private fun convertToReward(item: ItemStack) = if (item.displayName.removeColor() == "Enchanted Book") item.getLore()[2].removeColor() + else item.displayName.removeColor() + + private fun determinePrefix(index: Int, lastIndex: Int) = if (index == lastIndex) "└" else "├" + + private fun hasFoundPair( + first: SuperpairItem, + second: SuperpairItem, + ) = first.index != second.index && first.sameAs(second) + + // TODO extract logic greatly + private fun hasFoundMatch(firstItem: SuperpairItem) = + uncoveredItems.any { it.value.index != firstItem.index && it.value.sameAs(firstItem) } && + found.entries.none { + it.key.isAnyOf(FoundType.PAIR, FoundType.MATCH) && + it.value.any { data -> + firstItem.index.equalsOneOf(data.first?.index ?: -1, data.second?.index ?: -1) + } + } + + private fun isPowerUp(reward: String) = ExperimentationTableAPI.powerUpPattern.matches(reward) + + private fun isReward(reward: String) = + ExperimentationTableAPI.rewardPattern.matches(reward) || ExperimentationTableAPI.powerUpPattern.matches(reward) + + // TODO use repo patterns instead + private fun isWaiting(itemName: String) = + listOf("Click any button!", "Click a second button!", "Next button is instantly rewarded!").contains(itemName) + + private fun clicksSinceSeparator(list: MutableMap): Int { + val lastIndex = list.entries.indexOfLast { it.value == emptySuperpairItem } + return if (lastIndex != -1) list.size - 1 - lastIndex else -1 + } + + private fun isOutOfBounds(slot: Int, experiment: Experiment): Boolean = + slot <= experiment.startSlot || + slot >= experiment.endSlot || + (if (experiment.sideSpace == 1) slot in sideSpaces1 else slot in sideSpaces2) + + private fun SuperpairItem?.sameAs(other: SuperpairItem) = this?.reward == other.reward && this?.damage == other.damage + + private fun isEnabled() = + IslandType.PRIVATE_ISLAND.isInIsland() && config.superpairDisplay && ExperimentationTableAPI.getCurrentExperiment() != null +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt deleted file mode 100644 index cb3102ca8eed..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt +++ /dev/null @@ -1,277 +0,0 @@ -package at.hannibal2.skyhanni.features.inventory.experimentationtable - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.GuiContainerEvent.SlotClickEvent -import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.InventoryUtils -import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.RegexUtils.matches -import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings -import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import net.minecraft.item.ItemStack -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.time.Duration.Companion.milliseconds - -// TODO important: all use cases of listOf in combination with string needs to be gone. no caching, constant new list creation, and bad design. -@SkyHanniModule -object SuperpairExperimentInformationDisplay { - - private val config get() = SkyHanniMod.feature.inventory.experimentationTable - - private var display = emptyList() - - private var uncoveredAt = 0 - private var uncoveredItems = mutableListOf>() - private var possiblePairs = 0 - - data class Item(val index: Int, val name: String) - data class ItemPair(val first: Item, val second: Item) - - // TODO remove string. use enum instead! maybe even create new data type instead of map of pairs - private var found = mutableMapOf, String>() - - private var toCheck = mutableListOf>() - private var lastClicked = mutableListOf>() - private var lastClick = SimpleTimeMark.farPast() - private var currentExperiment = Experiment.NONE - private var instantFind = 0 - - private val sideSpaces1 = listOf(17, 18, 26, 27, 35, 36) - private val sideSpaces2 = listOf(16, 17, 18, 19, 25, 26, 27, 28, 34, 35, 36, 37) - - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - display = emptyList() - - uncoveredAt = 0 - uncoveredItems.clear() - possiblePairs = 0 - - found.clear() - toCheck.clear() - lastClicked.clear() - lastClick = SimpleTimeMark.farPast() - currentExperiment = Experiment.NONE - instantFind = 0 - } - - @SubscribeEvent - fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { - if (!isEnabled()) return - config.superpairDisplayPosition.renderStrings(display, posLabel = "Superpair Experiment Information") - display = checkItems(toCheck) - } - - @SubscribeEvent - fun onSlotClick(event: SlotClickEvent) { - if (!isEnabled()) return - currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return - - if (isOutOfBounds(event.slotId, currentExperiment)) return - val item = event.item ?: return - if (item.displayName.removeColor() == "?") return - val clicksItem = InventoryUtils.getItemAtSlotIndex(4) - - if (lastClicked.none { it.first == event.slotId && it.second == uncoveredAt } && lastClick.passedSince() > 100.milliseconds) { - if (clicksItem != null && clicksItem.displayName.removeColor().split(" ")[1] == "0") return - lastClicked.add(Pair(event.slotId, uncoveredAt)) - lastClick = SimpleTimeMark.now() - toCheck.add(event.slotId to uncoveredAt) - uncoveredAt += 1 - } - } - - private fun checkItems(check: MutableList>): List { - currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return listOf() - if (check.isEmpty()) return drawDisplay() - - for ((slot, uncovered) in check) { - val itemNow = InventoryUtils.getItemAtSlotIndex(slot) ?: return drawDisplay() - val itemName = itemNow.displayName.removeColor() - - if (isWaiting(itemName) || isOutOfBounds(slot, currentExperiment)) return drawDisplay() - - val reward = convertToReward(itemNow) - if (uncoveredItems.none { it.first == slot }) uncoveredItems.add(Pair(slot, reward)) - - when { - isPowerUp(reward) -> handlePowerUp(slot, reward) - isReward(itemName) -> handleReward(slot, uncovered, reward) - } - - possiblePairs = calculatePossiblePairs() - - val since = clicksSinceSeparator(lastClicked) - - if ((since >= 2 || (since == -1 && lastClicked.size >= 2)) && instantFind == 0) { - lastClicked.add(-1 to uncoveredAt) - uncoveredAt += 1 - } - toCheck.removeIf { it.first == slot } - - return drawDisplay() - } - possiblePairs = calculatePossiblePairs() - return drawDisplay() - } - - private fun handlePowerUp(slot: Int, reward: String) { - val item = toEither(Item(slot, reward)) - - found[item] = "Powerup" - possiblePairs-- - lastClicked.removeIf { it.first == slot } - uncoveredAt -= 1 - if (reward == "Instant Find") instantFind += 1 - } - - private fun handleReward(slot: Int, uncovered: Int, reward: String) { - val lastSlotClicked = - if (instantFind == 0 && lastClicked.none { it.first == -1 && it.second == uncovered - 1 } && lastClicked.size != 1) lastClicked.find { it.second == uncovered - 1 } - ?: return else lastClicked.find { it.second == uncovered } ?: return - - val lastItem = InventoryUtils.getItemAtSlotIndex(lastSlotClicked.first) ?: return - val itemClicked = InventoryUtils.getItemAtSlotIndex(slot) ?: return - - val lastItemName = convertToReward(lastItem) - - if (isWaiting(lastItemName)) return - - when { - instantFind >= 1 -> { - handleFoundPair(slot, reward, lastSlotClicked.first) - instantFind -= 1 - lastClicked.add(-1 to uncoveredAt) - uncoveredAt += 1 - } - - hasFoundPair(slot, lastSlotClicked.first, reward, lastItemName) && lastItem.itemDamage == itemClicked.itemDamage -> handleFoundPair( - slot, - reward, - lastSlotClicked.first, - ) - - hasFoundMatch(slot, reward) -> handleFoundMatch(slot, reward) - else -> handleNormalReward(slot, reward) - } - - } - - private fun handleFoundPair( - slot: Int, - reward: String, - lastSlotClicked: Int, - ) { - val pair = toEither(ItemPair(Item(slot, reward), Item(lastSlotClicked, reward))) - - found[pair] = "Pair" - found.entries.removeIf { - it.value == "Match" && right(it.key).first.index == slot - } - found.entries.removeIf { - it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == lastSlotClicked) - } - } - - private fun handleFoundMatch(slot: Int, reward: String) { - val match = uncoveredItems.find { it.second == reward }?.first ?: return - val pair = toEither(ItemPair(Item(slot, reward), Item(match, reward))) - - if (found.none { - listOf("Pair", "Match").contains(it.value) && (right(it.key).first.index == slot) - }) found[pair] = "Match" - found.entries.removeIf { it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == match) } - } - - private fun handleNormalReward(slot: Int, reward: String) { - val item = toEither(Item(slot, reward)) - - if (found.none { - listOf("Match", "Pair").contains(it.value) && (right(it.key).first.index == slot || right(it.key).second.index == slot) - } && found.none { it.value == "Normal" && left(it.key).index == slot }) found[item] = "Normal" - } - - private fun calculatePossiblePairs() = - ((currentExperiment.gridSize - 2) / 2) - found.filter { listOf("Pair", "Match", "Normal").contains(it.value) }.size - - private fun drawDisplay() = buildList { - add("§6Superpair Experimentation Data") - add("") - - val pairs = found.entries.filter { it.value == "Pair" } - val matches = found.entries.filter { it.value == "Match" } - val powerups = found.entries.filter { it.value == "Powerup" } - val normals = found.entries.filter { it.value == "Normal" } - - if (pairs.isNotEmpty()) add("§2Found") - for (pair in pairs) { - val prefix = determinePrefix(pairs.indexOf(pair), pairs.lastIndex) - add(" $prefix §a${right(pair.key).first.name}") - } - if (matches.isNotEmpty()) add("§eMatched") - for (match in matches) { - val prefix = determinePrefix(matches.indexOf(match), matches.lastIndex) - add(" $prefix §e${right(match.key).first.name}") - } - if (powerups.isNotEmpty()) add("§bPowerUp") - for (powerup in powerups) { - val prefix = determinePrefix(powerups.indexOf(powerup), powerups.size - 1) - add(" $prefix §b${left(powerup.key).name}") - } - val toAdd = mutableListOf() - if (possiblePairs >= 1) toAdd.add("§ePairs - $possiblePairs") - if (2 - powerups.size >= 1) toAdd.add("§bPowerUps - ${2 - powerups.size}") - if (normals.isNotEmpty()) toAdd.add("§7Normals - ${normals.size}") - - if (toAdd.isNotEmpty()) { - add("") - add("§4Not found") - } - for (string in toAdd) if (string != toAdd.last()) add(" ├ $string") else add(" └ $string") - } - - private fun convertToReward(item: ItemStack) = if (item.displayName.removeColor() == "Enchanted Book") item.getLore()[2].removeColor() - else item.displayName.removeColor() - - private fun determinePrefix(index: Int, lastIndex: Int) = if (index == lastIndex) "└" else "├" - - private fun hasFoundPair( - firstSlot: Int, - secondSlot: Int, - firstName: String, - secondName: String, - ) = firstSlot != secondSlot && firstName == secondName - - private fun hasFoundMatch(itemSlot: Int, reward: String) = - uncoveredItems.any { (slot, name) -> slot != itemSlot && name == reward } && found.none { - listOf("Pair", "Match").contains(it.value) && (right(it.key).first.index == itemSlot || right(it.key).second.index == itemSlot) - } - - private fun isPowerUp(reward: String) = ExperimentationTableAPI.powerUpPattern.matches(reward) - - private fun isReward(reward: String) = ExperimentationTableAPI.rewardPattern.matches(reward) - - private fun isWaiting(itemName: String) = - listOf("Click any button!", "Click a second button!", "Next button is instantly rewarded!").contains(itemName) - - private fun clicksSinceSeparator(list: MutableList>): Int { - val lastIndex = list.indexOfLast { it.first == -1 } - return if (lastIndex != -1) list.size - 1 - lastIndex else -1 - } - - private fun isOutOfBounds(slot: Int, experiment: Experiment): Boolean = - slot <= experiment.startSlot || slot >= experiment.endSlot || (if (experiment.sideSpace == 1) slot in sideSpaces1 else slot in sideSpaces2) - - // TODO remove left and right, use custom data type instead - private fun left(it: Pair): Item = it.first ?: Item(-1, "") - - private fun right(it: Pair): ItemPair = it.second ?: ItemPair(Item(-1, ""), Item(-1, "")) - - private fun toEither(it: Any): Pair = if (it is Item) it to null else null to it as ItemPair - - private fun isEnabled() = LorenzUtils.inSkyBlock && config.superpairDisplay && ExperimentationTableAPI.getCurrentExperiment() != null -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt index 72f3d13d4138..79d838f20c97 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt @@ -45,11 +45,11 @@ object MineshaftPityDisplay { profileStorage?.blocksBroken = value } - private var PityBlock.efficientMiner: Int - get() = minedBlocks.firstOrNull { it.pityBlock == this }?.efficientMiner ?: 0 + private var PityBlock.spreadBlocksBroken: Int + get() = minedBlocks.firstOrNull { it.pityBlock == this }?.spreadBlocksBroken ?: 0 set(value) { - minedBlocks.firstOrNull { it.pityBlock == this }?.let { it.efficientMiner = value } ?: run { - minedBlocks.add(PityData(this, efficientMiner = value)) + minedBlocks.firstOrNull { it.pityBlock == this }?.let { it.spreadBlocksBroken = value } ?: run { + minedBlocks.add(PityData(this, spreadBlocksBroken = value)) } } @@ -92,7 +92,7 @@ object MineshaftPityDisplay { if (originalOre != null) addOrPut(originalOre, -1) } .map { (block, amount) -> - block.getPityBlock()?.let { it.efficientMiner += amount } + block.getPityBlock()?.let { it.spreadBlocksBroken += amount } } update() @@ -105,7 +105,7 @@ object MineshaftPityDisplay { val pityCounter = calculateCounter() val chance = calculateChance(pityCounter) val counterUntilPity = MAX_COUNTER - pityCounter - val totalBlocks = PityBlock.entries.sumOf { it.blocksBroken + it.efficientMiner } + val totalBlocks = PityBlock.entries.sumOf { it.blocksBroken + it.spreadBlocksBroken } mineshaftTotalBlocks += totalBlocks mineshaftTotalCount++ @@ -124,7 +124,7 @@ object MineshaftPityDisplay { minedBlocks.forEach { add( " §7${it.pityBlock.displayName} mined: " + - "§e${it.blocksBroken.addSeparators()} [+${it.efficientMiner.addSeparators()} efficient miner]" + + "§e${it.blocksBroken.addSeparators()} [+${it.spreadBlocksBroken.addSeparators()} spread]" + " §6(${it.pityBlock.getPity().addSeparators()}/${counterUntilPity.addSeparators()})", ) } @@ -283,7 +283,7 @@ object MineshaftPityDisplay { data class PityData( @Expose val pityBlock: PityBlock, @Expose var blocksBroken: Int = 0, - @Expose var efficientMiner: Int = 0, + @Expose var spreadBlocksBroken: Int = 0, ) enum class PityBlock( @@ -339,7 +339,7 @@ object MineshaftPityDisplay { return entries.firstOrNull { oreType in it.oreTypes } } - fun PityBlock.getPity() = (blocksBroken + efficientMiner / 2.0) * multiplier + fun PityBlock.getPity() = (blocksBroken + spreadBlocksBroken / 2.0) * multiplier } } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt index 19383d4fad14..ad2baedbef87 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt @@ -72,7 +72,7 @@ object TunnelsMaps { field = value } - private var closedNote: GraphNode? = null + private var closestNode: GraphNode? = null private var path: Pair? = null private var possibleLocations = mapOf>() @@ -94,11 +94,11 @@ object TunnelsMaps { return it } - val closed = closedNote ?: return null + val closest = closestNode ?: return null val list = possibleLocations[name] ?: return null val offCooldown = list.filter { cooldowns[it]?.isInPast() != false } - val best = offCooldown.minByOrNull { GraphUtils.findShortestDistance(closed, it) } ?: list.minBy { + val best = offCooldown.minByOrNull { GraphUtils.findShortestDistance(closest, it) } ?: list.minBy { cooldowns[it] ?: SimpleTimeMark.farPast() } if (cooldowns[best]?.isInPast() != false) { @@ -394,11 +394,11 @@ object TunnelsMaps { fun onTick(event: LorenzTickEvent) { if (!isEnabled()) return if (checkGoalReached()) return - val prevClosed = closedNote - closedNote = graph.minBy { it.position.distanceSqToPlayer() } - val closest = closedNote ?: return + val prevclosest = closestNode + closestNode = graph.minBy { it.position.distanceSqToPlayer() } + val closest = closestNode ?: return val goal = goal ?: return - if (closest == prevClosed && goal == prevGoal) return + if (closest == prevclosest && goal == prevGoal) return val (path, distance) = GraphUtils.findShortestPathAsGraphWithDistance(closest, goal) val first = path.firstOrNull() val second = path.getOrNull(1) @@ -454,7 +454,7 @@ object TunnelsMaps { true, bezierPoint = 2.0, textSize = config.textSize.toDouble(), - showNoteNames = true, + showNodeNames = true, ) event.drawDynamicText( if (config.distanceFirst) { @@ -511,8 +511,8 @@ object TunnelsMaps { @SubscribeEvent fun onIslandChange(event: IslandChangeEvent) { - if (closedNote == null) return // Value that must be none null if it was active - closedNote = null + if (closestNode == null) return // Value that must be none null if it was active + closestNode = null clearPath() cooldowns.clear() goalReached = false diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt index faf3130b5ad8..439e434c146e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt @@ -20,7 +20,6 @@ import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor import at.hannibal2.skyhanni.utils.ConditionalUtils import at.hannibal2.skyhanni.utils.GraphUtils import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen -import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.roundTo @@ -54,7 +53,7 @@ object IslandAreas { hasMoved = true } - fun noteMoved() { + fun nodeMoved() { SkyHanniMod.coroutineScope.launch { updateNodes() } @@ -63,9 +62,9 @@ object IslandAreas { private fun updateNodes() { if (!isEnabled()) return val graph = IslandGraphs.currentIslandGraph ?: return - val closedNote = IslandGraphs.closedNote ?: return + val closestNode = IslandGraphs.closestNode ?: return - val (paths, map) = GraphUtils.findFastestPaths(graph, closedNote) { it.getAreaTag() != null } + val (paths, map) = GraphUtils.findFastestPaths(graph, closestNode) { it.getAreaTag() != null } this.paths = paths val finalNodes = mutableMapOf() @@ -129,14 +128,11 @@ object IslandAreas { } private fun buildDisplay() = buildList { - val closedNote = IslandGraphs.closedNote ?: return@buildList - val playerDiff = closedNote.position.distanceToPlayer() - var foundCurrentArea = false var foundAreas = 0 for ((node, diff) in nodes) { - val difference = diff + playerDiff + val difference = diff val tag = node.getAreaTag() ?: continue val name = node.name ?: continue @@ -160,7 +156,7 @@ object IslandAreas { } } - val distance = difference.roundTo(1) + val distance = difference.roundTo(0).toInt() val text = "$coloredName§7: §e$distance$suffix" if (!foundCurrentArea) { @@ -270,11 +266,11 @@ object IslandAreas { node.pathFind( displayName, color, - allowRerouting = true, onFound = { targetNode = null updatePosition() }, + allowRerouting = true, condition = { config.pathfinder.enabled }, ) hasMoved = true diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt index f3dc20df66e8..855a16394bb1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt @@ -94,7 +94,7 @@ object NavigationHelper { searchTerm: String, ): Map { val graph = IslandGraphs.currentIslandGraph ?: return emptyMap() - val closedNote = IslandGraphs.closedNote ?: return emptyMap() + val closestNode = IslandGraphs.closestNode ?: return emptyMap() val nodes = graph.nodes val distances = mutableMapOf() @@ -103,7 +103,7 @@ object NavigationHelper { val remainingTags = node.tags.filter { it in allowedTags } if (remainingTags.isEmpty()) continue if (name.lowercase().contains(searchTerm)) { - distances[node] = GraphUtils.findShortestDistance(closedNote, node) + distances[node] = GraphUtils.findShortestDistance(closestNode, node) } if (remainingTags.size != 1) { println("found node with invalid amount of tags: ${node.name} (${remainingTags.map { it.cleanName }}") diff --git a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt index 07fc7b81a2f4..fa6537046fc8 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/SkyHanniDebugsAndTests.kt @@ -126,7 +126,7 @@ object SkyHanniDebugsAndTests { val location = LorenzVec(x, y, z) testLocation = location if (args.getOrNull(3) == "pathfind") { - IslandGraphs.pathFind(location, "/shtestwaypoint", showGoalExact = true, condition = { true }) + IslandGraphs.pathFind(location, "/shtestwaypoint", condition = { true }) } ChatUtils.chat("set test waypoint") } diff --git a/src/main/java/at/hannibal2/skyhanni/test/graph/GraphEditor.kt b/src/main/java/at/hannibal2/skyhanni/test/graph/GraphEditor.kt index 9c9b5bb0693c..e724a8fe6c85 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/graph/GraphEditor.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/graph/GraphEditor.kt @@ -52,13 +52,13 @@ object GraphEditor { var activeNode: GraphingNode? = null set(value) { field = value - selectedEdge = findEdgeBetweenActiveAndClosed() + selectedEdge = findEdgeBetweenActiveAndClosest() checkDissolve() } - private var closedNode: GraphingNode? = null + private var closestNode: GraphingNode? = null set(value) { field = value - selectedEdge = findEdgeBetweenActiveAndClosed() + selectedEdge = findEdgeBetweenActiveAndClosest() } private var selectedEdge: GraphingEdge? = null @@ -88,7 +88,7 @@ object GraphEditor { private val nodeColor = LorenzColor.BLUE.addOpacity(200) private val activeColor = LorenzColor.GREEN.addOpacity(200) - private val closedColor = LorenzColor.YELLOW.addOpacity(200) + private val closestColor = LorenzColor.YELLOW.addOpacity(200) private val dijkstraColor = LorenzColor.LIGHT_PURPLE.addOpacity(200) private val edgeColor = LorenzColor.GOLD.addOpacity(150) @@ -168,7 +168,7 @@ object GraphEditor { private var dissolvePossible = false - private fun findEdgeBetweenActiveAndClosed(): GraphingEdge? = getEdgeIndex(activeNode, closedNode)?.let { edges[it] } + private fun findEdgeBetweenActiveAndClosest(): GraphingEdge? = getEdgeIndex(activeNode, closestNode)?.let { edges[it] } private fun checkDissolve() { if (activeNode == null) { @@ -189,7 +189,7 @@ object GraphEditor { if (!isEnabled()) return input() if (nodes.isEmpty()) return - closedNode = nodes.minBy { it.position.distanceSqToPlayer() } + closestNode = nodes.minBy { it.position.distanceSqToPlayer() } } private fun LorenzRenderWorldEvent.drawNode(node: GraphingNode) { @@ -245,8 +245,8 @@ object GraphEditor { } private fun GraphingNode.getNodeColor() = when (this) { - activeNode -> if (this == closedNode) ColorUtils.blendRGB(activeColor, closedColor, 0.5) else activeColor - closedNode -> closedColor + activeNode -> if (this == closestNode) ColorUtils.blendRGB(activeColor, closestColor, 0.5) else activeColor + closestNode -> closestColor in highlightedNodes -> dijkstraColor else -> nodeColor } @@ -341,12 +341,12 @@ object GraphEditor { toggleGhostPosition() } if (config.selectKey.isKeyClicked()) { - activeNode = if (activeNode == closedNode) { + activeNode = if (activeNode == closestNode) { feedBackInTutorial("De-selected active node.") null } else { feedBackInTutorial("Selected new active node.") - closedNode + closestNode } } if (config.selectRaycastKey.isKeyClicked()) { @@ -371,15 +371,15 @@ object GraphEditor { } activeNode = minimumNode } - if (activeNode != closedNode && config.connectKey.isKeyClicked()) { - val edge = getEdgeIndex(activeNode, closedNode) + if (activeNode != closestNode && config.connectKey.isKeyClicked()) { + val edge = getEdgeIndex(activeNode, closestNode) if (edge == null) { - addEdge(activeNode, closedNode) + addEdge(activeNode, closestNode) feedBackInTutorial("Added new edge.") } else { edges.removeAt(edge) checkDissolve() - selectedEdge = findEdgeBetweenActiveAndClosed() + selectedEdge = findEdgeBetweenActiveAndClosest() feedBackInTutorial("Removed edge.") } } @@ -476,14 +476,14 @@ object GraphEditor { } private fun addNode() { - val closedNode = closedNode - if (closedNode != null && closedNode.position.distanceSqToPlayer() < 9.0) { - if (closedNode == activeNode) { + val closestNode = closestNode + if (closestNode != null && closestNode.position.distanceSqToPlayer() < 9.0) { + if (closestNode == activeNode) { feedBackInTutorial("Removed node, since you where closer than 3 blocks from a the active node.") - nodes.remove(closedNode) - edges.removeIf { it.isInEdge(closedNode) } - if (closedNode == activeNode) activeNode = null - GraphEditor.closedNode = null + nodes.remove(closestNode) + edges.removeIf { it.isInEdge(closestNode) } + if (closestNode == activeNode) activeNode = null + GraphEditor.closestNode = null return } } @@ -521,7 +521,7 @@ object GraphEditor { val edge = GraphingEdge(node1, node2) if (edge.isInEdge(activeNode)) { checkDissolve() - selectedEdge = findEdgeBetweenActiveAndClosed() + selectedEdge = findEdgeBetweenActiveAndClosest() } edges.add(edge) } else false @@ -561,7 +561,7 @@ object GraphEditor { ) id = nodes.lastOrNull()?.id?.plus(1) ?: 0 checkDissolve() - selectedEdge = findEdgeBetweenActiveAndClosed() + selectedEdge = findEdgeBetweenActiveAndClosest() } private val highlightedNodes = mutableSetOf() @@ -569,7 +569,7 @@ object GraphEditor { private fun testDijkstra() { - val savedCurrent = closedNode ?: return + val savedCurrent = closestNode ?: return val savedActive = activeNode ?: return val compiled = compileGraph() @@ -594,7 +594,7 @@ object GraphEditor { nodes.clear() edges.clear() activeNode = null - closedNode = null + closestNode = null dissolvePossible = false ghostPosition = null } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/APIUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/APIUtils.kt index d28263af6c7d..f331ab3e3d17 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/APIUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/APIUtils.kt @@ -30,7 +30,7 @@ object APIUtils { private val ctx: SSLContext? = run { try { val myKeyStore = KeyStore.getInstance("JKS") - myKeyStore.load(APIUtils.javaClass.getResourceAsStream("/keystore.jks"), "changeit".toCharArray()) + myKeyStore.load(APIUtils.javaClass.getResourceAsStream("/skyhanni-keystore.jks"), "changeit".toCharArray()) val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) kmf.init(myKeyStore, null) diff --git a/src/main/java/at/hannibal2/skyhanni/utils/MobUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/MobUtils.kt index db04ddd7cdf8..10d9e2c940f4 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/MobUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/MobUtils.kt @@ -25,10 +25,10 @@ object MobUtils { fun getArmorStandByRangeAll(entity: Entity, range: Double) = EntityUtils.getEntitiesNearby(entity.getLorenzVec(), range) - fun getClosedArmorStand(entity: Entity, range: Double) = + fun getClosestArmorStand(entity: Entity, range: Double) = getArmorStandByRangeAll(entity, range).sortedBy { it.distanceTo(entity) }.firstOrNull() - fun getClosedArmorStandWithName(entity: Entity, range: Double, name: String) = + fun getClosestArmorStandWithName(entity: Entity, range: Double, name: String) = getArmorStandByRangeAll(entity, range).filter { it.cleanName().startsWith(name) } .sortedBy { it.distanceTo(entity) }.firstOrNull() @@ -71,9 +71,10 @@ object MobUtils { val pos = entity.getPositionEyes(partialTicks).toLorenzVec() + offset val look = entity.getLook(partialTicks).toLorenzVec().normalize() val possibleEntities = MobData.entityToMob.filterKeys { - it !is EntityArmorStand && it.entityBoundingBox.rayIntersects( - pos, look - ) + it !is EntityArmorStand && + it.entityBoundingBox.rayIntersects( + pos, look + ) }.values if (possibleEntities.isEmpty()) return null return possibleEntities.distinct().sortedBy { it.baseEntity.distanceTo(pos) } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt index d22ecc85e12c..cf2339bf3c42 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/RenderUtils.kt @@ -1279,7 +1279,7 @@ object RenderUtils { waypointColor: Color = (path.lastOrNull()?.name?.getFirstColorCode()?.toLorenzColor() ?: LorenzColor.WHITE).toColor(), bezierPoint: Double = 1.0, - showNoteNames: Boolean = false, + showNodeNames: Boolean = false, markLastBlock: Boolean = true, ) { if (path.isEmpty()) return @@ -1302,7 +1302,7 @@ object RenderUtils { bezierPoint, ) } - if (showNoteNames) { + if (showNodeNames) { path.filter { it.name?.isNotEmpty() == true }.forEach { this.drawDynamicText(it.position, it.name!!, textSize) } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt index 5cf3ec2e51f7..34b86f63efdb 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeUtils.kt @@ -34,6 +34,11 @@ object TimeUtils { val largestNonZeroUnit = parts.firstNotNullOfOrNull { if (it.value != 0) it.key else null } ?: TimeUnit.SECOND + if (absoluteValue < 1.seconds) { + val formattedMillis = (millis / 100).toInt() + return "0.${formattedMillis}s" + } + var currentUnits = 0 val result = buildString { for ((unit, value) in parts) { diff --git a/src/main/resources/mykeystore.jks b/src/main/resources/skyhanni-keystore.jks similarity index 100% rename from src/main/resources/mykeystore.jks rename to src/main/resources/skyhanni-keystore.jks