Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement + Fix: Pathfind Rendering #2634

Merged
merged 4 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 46 additions & 93 deletions src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

/**
Expand Down Expand Up @@ -104,8 +102,9 @@ 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
Expand All @@ -115,7 +114,6 @@ object IslandGraphs {
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) {
Expand Down Expand Up @@ -215,15 +213,16 @@ 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()
}
}

private fun reset() {
stop()
closedNote = null
pathfindClosestNode = null
closestNode = null
}

@SubscribeEvent
Expand All @@ -236,7 +235,7 @@ object IslandGraphs {
}

private fun handleTick() {
val prevClosed = closedNote
val prevClosest = pathfindClosestNode

currentTarget?.let {
if (it.distanceToPlayer() < 3) {
Expand All @@ -252,39 +251,39 @@ 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 = newGraph
newNodes.getOrNull(1)?.let {
secondClosestNode = it
}
setFastestPath(newGraph to newGraph.totalLenght(), setPath = false)
return true
}

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()
Expand All @@ -307,7 +306,7 @@ object IslandGraphs {
private fun Graph.totalLenght(): Double = nodes.zipWithNext().sumOf { (a, b) -> a.position.distance(b.position) }

private fun handlePositionChange() {
val secondClosestNode = secondClosedNote ?: return
val secondClosestNode = secondClosestNode ?: return
distanceToNextNode = secondClosestNode.position.distanceToPlayer()
updateChat()
}
Expand Down Expand Up @@ -337,7 +336,7 @@ object IslandGraphs {
nodes.add(0, GraphNode(0, LocationUtils.playerLocation()))
}
if (setPath) {
this.fastestPath = Graph(cutByMaxDistance(nodes, 3.0))
this.fastestPath = Graph(cutByMaxDistance(nodes, 2.0))
}

val diff = fastestPath.getOrNull(1)?.let {
Expand All @@ -347,22 +346,22 @@ object IslandGraphs {
updateChat()
}

private fun onNewNote() {
private fun onNewNode() {
// TODO create an event
IslandAreas.noteMoved()
IslandAreas.nodeMoved()
if (shouldAllowRerouting) {
tryRerouting()
}
}

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)
}
}

Expand Down Expand Up @@ -396,7 +395,7 @@ object IslandGraphs {
reset()
currentTargetNode = this
shouldAllowRerouting = allowRerouting
pathFind0(location = position, label, color, onFound, showGoalExact = false, condition)
pathFind0(location = position, label, color, onFound, condition)
}

/**
Expand All @@ -406,35 +405,31 @@ 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(
location: LorenzVec,
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(
location: LorenzVec,
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!!) }
Expand Down Expand Up @@ -473,26 +468,27 @@ object IslandGraphs {
var path = fastestPath ?: return

if (path.nodes.size > 1) {
val hideNearby = if (Minecraft.getMinecraft().thePlayer.onGround) 5 else 7
val hideNearby = if (Minecraft.getMinecraft().thePlayer.onGround) 3 else 5
path = Graph(path.nodes.takeLastWhile { it.position.distanceToPlayer() > hideNearby })
}
// graph = skipNodes(graph) ?: graph

// 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
Expand Down Expand Up @@ -524,47 +520,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)
}
}
24 changes: 15 additions & 9 deletions src/main/java/at/hannibal2/skyhanni/data/mob/IslandExceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ?: "") ->
Expand Down Expand Up @@ -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),
Expand All @@ -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) }
Expand All @@ -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)

Expand Down Expand Up @@ -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"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ object PowderMiningChatFilter {

val patternGroup = RepoPattern.group("filter.powdermining")

// TODO rename to "openedRewards" ?
private var unclosedRewards = false

/**
Expand Down
Loading
Loading