diff options
author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2024-10-02 13:50:45 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-02 13:50:45 +0200 |
commit | ab7b3269eb8a5b3869331fa94663b1ddfebe80b2 (patch) | |
tree | 3b2a7c01440d994776e4c8970d524fc1f7949a65 /src/main/java/at/hannibal2/skyhanni/data | |
parent | 0864f1e1de572b955f356053ad9cb73be24d5683 (diff) | |
download | skyhanni-ab7b3269eb8a5b3869331fa94663b1ddfebe80b2.tar.gz skyhanni-ab7b3269eb8a5b3869331fa94663b1ddfebe80b2.tar.bz2 skyhanni-ab7b3269eb8a5b3869331fa94663b1ddfebe80b2.zip |
Improvement: Pathfind Rendering (#2634)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/data')
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt | 180 | ||||
-rw-r--r-- | src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt | 24 |
2 files changed, 83 insertions, 121 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt index 73915c22d..9829b4ec9 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<Graph, Double>, 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<GraphNode>() - 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 2acbe3546..eed2d5e70 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")) |