aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/data
diff options
context:
space:
mode:
authorhannibal2 <24389977+hannibal002@users.noreply.github.com>2024-10-02 13:50:45 +0200
committerGitHub <noreply@github.com>2024-10-02 13:50:45 +0200
commitab7b3269eb8a5b3869331fa94663b1ddfebe80b2 (patch)
tree3b2a7c01440d994776e4c8970d524fc1f7949a65 /src/main/java/at/hannibal2/skyhanni/data
parent0864f1e1de572b955f356053ad9cb73be24d5683 (diff)
downloadskyhanni-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.kt180
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt24
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"))