Skip to content

Commit 86d17d5

Browse files
committed
Optimized threading and graph renderer
1 parent 7339f60 commit 86d17d5

File tree

7 files changed

+129
-62
lines changed

7 files changed

+129
-62
lines changed

common/src/main/kotlin/com/lambda/module/modules/movement/Pathfinder.kt

Lines changed: 86 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@
1717

1818
package com.lambda.module.modules.movement
1919

20+
import com.lambda.Lambda
2021
import com.lambda.context.SafeContext
2122
import com.lambda.event.events.MovementEvent
2223
import com.lambda.event.events.RenderEvent
2324
import com.lambda.event.events.RotationEvent
2425
import com.lambda.event.events.TickEvent
2526
import com.lambda.event.listener.SafeListener.Companion.listen
27+
import com.lambda.graphics.gl.Matrices
2628
import com.lambda.graphics.renderer.esp.builders.buildFilled
2729
import com.lambda.interaction.request.rotation.Rotation
2830
import com.lambda.interaction.request.rotation.Rotation.Companion.rotationTo
@@ -41,20 +43,23 @@ import com.lambda.pathing.goal.SimpleGoal
4143
import com.lambda.pathing.move.MoveFinder.moveOptions
4244
import com.lambda.pathing.move.NodeType
4345
import com.lambda.pathing.move.TraverseMove
44-
import com.lambda.threading.runConcurrent
4546
import com.lambda.threading.runSafe
47+
import com.lambda.threading.runSafeConcurrent
4648
import com.lambda.util.Communication.info
4749
import com.lambda.util.Formatting.string
4850
import com.lambda.util.math.setAlpha
4951
import com.lambda.util.player.MovementUtils.buildMovementInput
5052
import com.lambda.util.player.MovementUtils.mergeFrom
5153
import com.lambda.util.world.FastVector
54+
import com.lambda.util.world.WorldUtils.hasSupport
5255
import com.lambda.util.world.fastVectorOf
5356
import com.lambda.util.world.toBlockPos
5457
import com.lambda.util.world.toFastVec
5558
import com.lambda.util.world.x
5659
import com.lambda.util.world.y
5760
import com.lambda.util.world.z
61+
import kotlinx.coroutines.delay
62+
import net.minecraft.util.math.BlockPos
5863
import net.minecraft.util.math.Box
5964
import net.minecraft.util.math.Vec3d
6065
import java.awt.Color
@@ -68,15 +73,10 @@ object Pathfinder : Module(
6873
description = "Get from A to B",
6974
defaultTags = setOf(ModuleTag.MOVEMENT)
7075
) {
76+
private val targetPos by setting("Target", BlockPos(0, 78, 0))
7177
private val pathing = PathingSettings(this)
7278

73-
private fun heuristic(u: FastVector): Double =
74-
(abs(u.x) + abs(u.y) + abs(u.z)).toDouble()
75-
76-
private fun heuristic(u: FastVector, v: FastVector): Double =
77-
(abs(u.x - v.x) + abs(u.y - v.y) + abs(u.z - v.z)).toDouble()
78-
79-
private val target = fastVectorOf(0, 91, -4)
79+
private val target: FastVector get() = targetPos.toFastVec()
8080
private val graph = LazyGraph { origin ->
8181
runSafe {
8282
moveOptions(origin, ::heuristic, pathing).associate { it.pos to it.cost }
@@ -88,27 +88,40 @@ object Pathfinder : Module(
8888
private var currentTarget: Vec3d? = null
8989
private var integralError = Vec3d.ZERO
9090
private var lastError = Vec3d.ZERO
91-
private var calculating = false
91+
private var needsUpdate = false
92+
private var currentStart = BlockPos.ORIGIN.toFastVec()
93+
94+
private fun heuristic(u: FastVector): Double =
95+
(abs(u.x) + abs(u.y) + abs(u.z)).toDouble()
96+
97+
private fun heuristic(u: FastVector, v: FastVector): Double =
98+
(abs(u.x - v.x) + abs(u.y - v.y) + abs(u.z - v.z)).toDouble()
9299

93100
init {
94101
onEnable {
95102
integralError = Vec3d.ZERO
96103
lastError = Vec3d.ZERO
97-
calculating = false
98104
coarsePath = Path()
99105
refinedPath = Path()
100106
currentTarget = null
101107
graph.clear()
102108
dStar.initialize()
103-
dStar.updateStart(player.pos.toFastVec())
109+
needsUpdate = true
110+
currentStart = player.blockPos.toFastVec()
111+
startBackgroundThread()
112+
}
113+
114+
onDisable {
115+
graph.clear()
104116
}
105117

106118
listen<TickEvent.Pre> {
119+
val playerPos = player.blockPos
120+
if (player.isOnGround && hasSupport(playerPos)) {
121+
currentStart = playerPos.toFastVec()
122+
needsUpdate = true
123+
}
107124
updateTargetNode()
108-
109-
if (calculating) return@listen
110-
111-
updatePaths()
112125
}
113126

114127
// listen<WorldEvent.BlockUpdate.Client> {
@@ -161,6 +174,30 @@ object Pathfinder : Module(
161174
if (pathing.renderCoarsePath) coarsePath.render(event.renderer, Color.YELLOW)
162175
if (pathing.renderRefinedPath) refinedPath.render(event.renderer, Color.GREEN)
163176
if (pathing.renderGoal) event.renderer.buildFilled(Box(target.toBlockPos()), Color.PINK.setAlpha(0.25))
177+
if (pathing.renderGraph) graph.render(event.renderer)
178+
}
179+
180+
listen<RenderEvent.World> {
181+
if (!pathing.renderGraph) return@listen
182+
183+
Matrices.push {
184+
val c = mc.gameRenderer.camera.pos.negate()
185+
translate(c.x, c.y, c.z)
186+
graph.buildDebugInfo()
187+
}
188+
}
189+
}
190+
191+
private fun startBackgroundThread() {
192+
runSafeConcurrent {
193+
while (isEnabled) {
194+
if (!needsUpdate) {
195+
delay(50L)
196+
continue
197+
}
198+
needsUpdate = false
199+
updatePaths()
200+
}
164201
}
165202
}
166203

@@ -176,58 +213,49 @@ object Pathfinder : Module(
176213

177214
private fun SafeContext.updatePaths() {
178215
val goal = SimpleGoal(target)
179-
val start = player.blockPos.toFastVec()
180216
when (pathing.algorithm) {
181-
PathingConfig.PathingAlgorithm.A_STAR -> updateAStar(start, goal)
182-
PathingConfig.PathingAlgorithm.D_STAR_LITE -> updateDStar()
217+
PathingConfig.PathingAlgorithm.A_STAR -> updateAStar(currentStart, goal)
218+
PathingConfig.PathingAlgorithm.D_STAR_LITE -> updateDStar(currentStart, goal)
183219
}
184220
}
185221

186222
private fun SafeContext.updateAStar(start: FastVector, goal: SimpleGoal) {
187-
runConcurrent {
188-
calculating = true
189-
val long: Path
190-
val aStar = measureTimeMillis {
191-
long = findPathAStar(start, goal, pathing)
192-
}
193-
val short: Path
194-
val thetaStar = measureTimeMillis {
195-
short = if (pathing.refinePath) {
196-
thetaStarClearance(long, pathing)
197-
} else long
198-
}
199-
info("A* (Length: ${long.length().string} Nodes: ${long.size} T: $aStar ms) and \u03b8* (Length: ${short.length().string} Nodes: ${short.size} T: $thetaStar ms)")
200-
println("Long: $long | Short: $short")
201-
short.moves.removeFirstOrNull()
202-
coarsePath = long
203-
refinedPath = short
204-
// calculating = false
223+
val long: Path
224+
val aStar = measureTimeMillis {
225+
long = findPathAStar(start, goal, pathing)
205226
}
227+
val short: Path
228+
val thetaStar = measureTimeMillis {
229+
short = if (pathing.refinePath) {
230+
thetaStarClearance(long, pathing)
231+
} else long
232+
}
233+
info("A* (Length: ${long.length().string} Nodes: ${long.size} T: $aStar ms) and \u03b8* (Length: ${short.length().string} Nodes: ${short.size} T: $thetaStar ms)")
234+
// println("Long: $long | Short: $short")
235+
short.moves.removeFirstOrNull()
236+
coarsePath = long
237+
refinedPath = short
206238
}
207239

208-
private fun SafeContext.updateDStar() {
209-
calculating = true
210-
runConcurrent {
211-
val long: Path
212-
val dStar = measureTimeMillis {
213-
// if (start dist dstar.start > 3) dstar.updateStart(start)
214-
dStar.computeShortestPath(pathing.cutoffTimeout)
215-
val nodes = dStar.getPath().map { TraverseMove(it, 0.0, NodeType.OPEN, 0.0, 0.0) }
216-
long = Path(ArrayDeque(nodes))
217-
}
218-
val short: Path
219-
val thetaStar = measureTimeMillis {
220-
short = if (pathing.refinePath) {
221-
thetaStarClearance(long, pathing)
222-
} else long
223-
}
224-
info("Lazy D* Lite (Length: ${long.length().string} Nodes: ${long.size} Graph Size: ${graph.size} T: $dStar ms) and \u03b8* (Length: ${short.length().string} Nodes: ${short.size} T: $thetaStar ms)")
225-
println("Long: $long | Short: $short")
226-
short.moves.removeFirstOrNull()
227-
coarsePath = long
228-
refinedPath = short
229-
// calculating = false
240+
private fun SafeContext.updateDStar(start: FastVector, goal: SimpleGoal) {
241+
val long: Path
242+
val dStar = measureTimeMillis {
243+
dStar.updateStart(start)
244+
dStar.computeShortestPath(pathing.cutoffTimeout)
245+
val nodes = dStar.getPath().map { TraverseMove(it, 0.0, NodeType.OPEN, 0.0, 0.0) }
246+
long = Path(ArrayDeque(nodes))
247+
}
248+
val short: Path
249+
val thetaStar = measureTimeMillis {
250+
short = if (pathing.refinePath) {
251+
thetaStarClearance(long, pathing)
252+
} else long
230253
}
254+
info("Lazy D* Lite (Length: ${long.length().string} Nodes: ${long.size} Graph Size: ${graph.size} T: $dStar ms) and \u03b8* (Length: ${short.length().string} Nodes: ${short.size} T: $thetaStar ms)")
255+
// println("Long: $long | Short: $short")
256+
short.moves.removeFirstOrNull()
257+
coarsePath = long
258+
refinedPath = short
231259
}
232260

233261
private fun SafeContext.calculatePID(target: Vec3d): Vec3d {

common/src/main/kotlin/com/lambda/pathing/PathingConfig.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface PathingConfig {
4242
val renderCoarsePath: Boolean
4343
val renderRefinedPath: Boolean
4444
val renderGoal: Boolean
45+
val renderGraph: Boolean
4546
val assumeJesus: Boolean
4647

4748
enum class PathingAlgorithm(override val displayName: String) : NamedEnum {

common/src/main/kotlin/com/lambda/pathing/PathingSettings.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@ class PathingSettings(
5151
override val renderCoarsePath by c.setting("Render Coarse Path", false) { vis() && page == Page.Misc }
5252
override val renderRefinedPath by c.setting("Render Refined Path", true) { vis() && page == Page.Misc }
5353
override val renderGoal by c.setting("Render Goal", true) { vis() && page == Page.Misc }
54+
override val renderGraph by c.setting("Render Graph", false) { vis() && page == Page.Misc }
5455
override val assumeJesus by c.setting("Assume Jesus", false) { vis() && page == Page.Misc }
5556
}

common/src/main/kotlin/com/lambda/pathing/dstar/DStarLite.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ class DStarLite(
152152
* all vertices in the queue are re-keyed.
153153
*/
154154
fun updateStart(newStart: FastVector) {
155+
if (newStart == start) return
155156
val oldStart = start
156157
start = newStart
157158
km += heuristic(oldStart, start)

common/src/main/kotlin/com/lambda/pathing/dstar/LazyGraph.kt

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@
1717

1818
package com.lambda.pathing.dstar
1919

20+
import com.lambda.graphics.renderer.esp.builders.buildLine
21+
import com.lambda.graphics.renderer.esp.global.StaticESP
2022
import com.lambda.util.world.FastVector
23+
import com.lambda.util.world.toCenterVec3d
24+
import com.lambda.util.world.toVec3d
25+
import java.awt.Color
26+
import java.util.concurrent.ConcurrentHashMap
27+
import java.util.concurrent.ConcurrentMap
2128

2229
/**
2330
* A 3D graph that uses FastVector (a Long) to represent 3D nodes.
@@ -35,8 +42,8 @@ import com.lambda.util.world.FastVector
3542
class LazyGraph(
3643
private val nodeInitializer: (FastVector) -> Map<FastVector, Double>
3744
) {
38-
private val successors = hashMapOf<FastVector, MutableMap<FastVector, Double>>()
39-
private val predecessors = hashMapOf<FastVector, MutableMap<FastVector, Double>>()
45+
private val successors = ConcurrentHashMap<FastVector, MutableMap<FastVector, Double>>()
46+
private val predecessors = ConcurrentHashMap<FastVector, MutableMap<FastVector, Double>>()
4047
private val dirtyNodes = mutableSetOf<FastVector>()
4148

4249
val size get() = successors.size
@@ -69,10 +76,34 @@ class LazyGraph(
6976
/** Returns the cost of the edge from u to v (or ∞ if none exists) */
7077
fun cost(u: FastVector, v: FastVector): Double = successors(u)[v] ?: Double.POSITIVE_INFINITY
7178

72-
fun contains(u: FastVector): Boolean = u in successors
79+
fun contains(u: FastVector): Boolean = successors.containsKey(u)
7380

7481
fun clear() {
7582
successors.clear()
7683
predecessors.clear()
7784
}
85+
86+
fun render(renderer: StaticESP) {
87+
successors.entries.take(1000).forEach { (origin, neighbors) ->
88+
neighbors.forEach { (neighbor, cost) ->
89+
renderer.buildLine(origin.toCenterVec3d(), neighbor.toCenterVec3d(), Color.PINK)
90+
}
91+
}
92+
}
93+
94+
fun buildDebugInfo() {
95+
// val projection = buildWorldProjection(blockPos, 0.4, Matrices.ProjRotationMode.TO_CAMERA)
96+
// withVertexTransform(projection) {
97+
// val lines = arrayOf(
98+
// ""
99+
// )
100+
//
101+
// var height = -0.5 * lines.size * (FontRenderer.getHeight() + 2)
102+
//
103+
// lines.forEach {
104+
// drawString(it, Vec2d(-FontRenderer.getWidth(it) * 0.5, height))
105+
// height += FontRenderer.getHeight() + 2
106+
// }
107+
// }
108+
}
78109
}

common/src/main/kotlin/com/lambda/util/world/Position.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ fun Vec3d.toFastVec(): FastVector = fastVectorOf(x.toLong(), y.toLong(), z.toLon
258258
*/
259259
fun FastVector.toVec3d(): Vec3d = Vec3d(x.toDouble(), y.toDouble(), z.toDouble())
260260

261+
/**
262+
* [FastVector] to a centered [Vec3d]
263+
*/
264+
fun FastVector.toCenterVec3d(): Vec3d = Vec3d(x + 0.5, y + 0.5, z + 0.5)
265+
261266
/**
262267
* Converts the [FastVector] into a [BlockPos].
263268
*/

common/src/main/kotlin/com/lambda/util/world/WorldUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object WorldUtils {
7171
private fun SafeContext.hasClearance(pos: BlockPos) =
7272
blockState(pos).isAir && blockState(pos.up()).isAir
7373

74-
private fun SafeContext.hasSupport(pos: BlockPos) =
74+
fun SafeContext.hasSupport(pos: BlockPos) =
7575
blockState(pos.down()).isSideSolidFullSquare(world, pos.down(), Direction.UP)
7676

7777
fun Vec3d.playerBox(): Box =

0 commit comments

Comments
 (0)