Skip to content

Commit a6f39f6

Browse files
committed
Improved renderer
1 parent fb1ded1 commit a6f39f6

File tree

7 files changed

+166
-99
lines changed

7 files changed

+166
-99
lines changed

common/src/main/kotlin/com/lambda/command/commands/PathCommand.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ object PathCommand : LambdaCommand(
4242
execute {
4343
val dirty = fastVectorOf(x().value(), y().value(), z().value())
4444
Pathfinder.graph.markDirty(dirty)
45-
Pathfinder.graph.updateDirtyNode(dirty)
45+
// Pathfinder.dStar.updateGraph()
4646
this@PathCommand.info("Marked ${dirty.string} as dirty")
4747
}
4848
}
@@ -60,8 +60,8 @@ object PathCommand : LambdaCommand(
6060
required(literal("update")) {
6161
execute {
6262
Pathfinder.needsUpdate = true
63-
this@PathCommand.info("Updating graph")
63+
this@PathCommand.info("Marked graph for update")
6464
}
6565
}
6666
}
67-
}
67+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ object Pathfinder : Module(
8282
moveOptions(origin, ::heuristic, pathing).associate { it.pos to it.cost }
8383
} ?: emptyMap()
8484
}
85-
private val dStar = DStarLite(graph, fastVectorOf(0, 0, 0), target, ::heuristic)
85+
val dStar = DStarLite(graph, fastVectorOf(0, 0, 0), target, ::heuristic)
8686
private var coarsePath = Path()
8787
private var refinedPath = Path()
8888
private var currentTarget: Vec3d? = null
@@ -186,7 +186,7 @@ object Pathfinder : Module(
186186
Matrices.push {
187187
val c = mc.gameRenderer.camera.pos.negate()
188188
translate(c.x, c.y, c.z)
189-
graph.buildDebugInfoRenderer(pathing)
189+
dStar.buildDebugInfoRenderer(pathing)
190190
}
191191
}
192192
}
@@ -244,7 +244,7 @@ object Pathfinder : Module(
244244
val dStar = measureTimeMillis {
245245
dStar.updateStart(start)
246246
dStar.computeShortestPath(pathing.cutoffTimeout)
247-
val nodes = dStar.path.map { TraverseMove(it, 0.0, NodeType.OPEN, 0.0, 0.0) }
247+
val nodes = dStar.path(pathing.maxPathLength).map { TraverseMove(it, 0.0, NodeType.OPEN, 0.0, 0.0) }
248248
long = Path(ArrayDeque(nodes))
249249
}
250250
val short: Path

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,20 @@ interface PathingConfig {
2424
val algorithm: PathingAlgorithm
2525
val cutoffTimeout: Long
2626
val maxFallHeight: Double
27+
val mlg: Boolean
28+
val useWaterBucket: Boolean
29+
val useLavaBucket: Boolean
30+
val useBoat: Boolean
31+
val maxPathLength: Int
2732

2833
val refinePath: Boolean
34+
val useThetaStar: Boolean
2935
val shortcutLength: Int
3036
val clearancePrecision: Double
3137
val findShortcutJumps: Boolean
38+
val maxJumpDistance: Double
39+
val spline: Spline
40+
val epsilon: Double
3241

3342
val moveAlongPath: Boolean
3443
val kP: Double
@@ -43,13 +52,22 @@ interface PathingConfig {
4352
val renderRefinedPath: Boolean
4453
val renderGoal: Boolean
4554
val renderGraph: Boolean
46-
val renderCost: Boolean
4755
val renderPositions: Boolean
56+
val renderCost: Boolean
57+
val renderG: Boolean
58+
val renderRHS: Boolean
4859
val maxRenderObjects: Int
60+
val fontScale: Double
4961
val assumeJesus: Boolean
5062

5163
enum class PathingAlgorithm(override val displayName: String) : NamedEnum {
5264
A_STAR("A*"),
5365
D_STAR_LITE("Lazy D* Lite"),
5466
}
67+
68+
enum class Spline {
69+
None,
70+
CatmullRom,
71+
CubicBezier,
72+
}
5573
}

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,28 @@ class PathingSettings(
2525
vis: () -> Boolean = { true }
2626
) : PathingConfig {
2727
enum class Page {
28-
Pathfinding, Refinement, Movement, Rotation, Misc
28+
Pathfinding, Refinement, Movement, Rotation, Debug, Misc
2929
}
3030

3131
private val page by c.setting("Pathing Page", Page.Pathfinding, "Current page", vis)
3232

3333
override val algorithm by c.setting("Algorithm", PathingConfig.PathingAlgorithm.A_STAR) { vis() && page == Page.Pathfinding }
3434
override val cutoffTimeout by c.setting("Cutoff Timeout", 500L, 1L..2000L, 10L, "Timeout of path calculation", " ms") { vis() && page == Page.Pathfinding }
3535
override val maxFallHeight by c.setting("Max Fall Height", 3.0, 0.0..30.0, 0.5) { vis() && page == Page.Pathfinding }
36+
override val mlg by c.setting("Do MLG", false) { vis() && page == Page.Pathfinding }
37+
override val useWaterBucket by c.setting("Use Water Bucket", true) { vis() && page == Page.Pathfinding && mlg }
38+
override val useLavaBucket by c.setting("Use Lava Bucket", true) { vis() && page == Page.Pathfinding && mlg }
39+
override val useBoat by c.setting("Use Boat", true) { vis() && page == Page.Pathfinding && mlg }
40+
override val maxPathLength by c.setting("Max Path Length", 10_000, 1..100_000, 100) { vis() && page == Page.Pathfinding }
3641

37-
override val refinePath by c.setting("Refine Path with θ*", true) { vis() && page == Page.Refinement }
38-
override val shortcutLength by c.setting("Shortcut Length", 15, 1..100, 1) { vis() && refinePath && page == Page.Refinement }
39-
override val clearancePrecision by c.setting("Clearance Precision", 0.1, 0.0..1.0, 0.01) { vis() && refinePath && page == Page.Refinement }
42+
override val refinePath by c.setting("Refine Path", true) { vis() && page == Page.Refinement }
43+
override val useThetaStar by c.setting("Use θ* (Any Angle)", true) { vis() && refinePath && page == Page.Refinement }
44+
override val shortcutLength by c.setting("Shortcut Length", 15, 1..100, 1) { vis() && refinePath && useThetaStar && page == Page.Refinement }
45+
override val clearancePrecision by c.setting("Clearance Precision", 0.1, 0.0..1.0, 0.01) { vis() && refinePath && useThetaStar && page == Page.Refinement }
4046
override val findShortcutJumps by c.setting("Find Shortcut Jumps", true) { vis() && refinePath && page == Page.Refinement }
47+
override val maxJumpDistance by c.setting("Max Jump Distance", 4.0, 1.0..5.0, 0.1) { vis() && refinePath && findShortcutJumps && page == Page.Refinement }
48+
override val spline by c.setting("Use Splines", PathingConfig.Spline.CatmullRom) { vis() && refinePath && page == Page.Refinement }
49+
override val epsilon by c.setting("ε", 0.3, 0.0..1.0, 0.01) { vis() && refinePath && spline != PathingConfig.Spline.None && page == Page.Refinement }
4150

4251
override val moveAlongPath by c.setting("Move Along Path", true) { vis() && page == Page.Movement }
4352
override val kP by c.setting("P Gain", 0.5, 0.0..2.0, 0.01) { vis() && moveAlongPath && page == Page.Movement }
@@ -48,12 +57,16 @@ class PathingSettings(
4857

4958
override val rotation = RotationSettings(c) { page == Page.Rotation }
5059

51-
override val renderCoarsePath by c.setting("Render Coarse Path", false) { vis() && page == Page.Misc }
52-
override val renderRefinedPath by c.setting("Render Refined Path", true) { vis() && page == Page.Misc }
53-
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 }
55-
override val renderCost by c.setting("Render Cost", false) { vis() && page == Page.Misc && renderGraph }
56-
override val renderPositions by c.setting("Render Positions", false) { vis() && page == Page.Misc && renderGraph }
57-
override val maxRenderObjects by c.setting("Max Render Objects", 1000, 0..100_000) { vis() && page == Page.Misc && renderGraph }
60+
override val renderCoarsePath by c.setting("Render Coarse Path", false) { vis() && page == Page.Debug }
61+
override val renderRefinedPath by c.setting("Render Refined Path", true) { vis() && page == Page.Debug }
62+
override val renderGoal by c.setting("Render Goal", true) { vis() && page == Page.Debug }
63+
override val renderGraph by c.setting("Render Graph", false) { vis() && page == Page.Debug }
64+
override val renderPositions by c.setting("Render Positions", false) { vis() && page == Page.Debug && renderGraph }
65+
override val renderCost by c.setting("Render Cost", false) { vis() && page == Page.Debug && renderGraph }
66+
override val renderG by c.setting("Render G", false) { vis() && page == Page.Debug && renderGraph }
67+
override val renderRHS by c.setting("Render RHS", false) { vis() && page == Page.Debug && renderGraph }
68+
override val maxRenderObjects by c.setting("Max Render Objects", 1000, 0..10_000, 100) { vis() && page == Page.Debug && renderGraph }
69+
override val fontScale by c.setting("Font Scale", 0.4, 0.0..2.0, 0.01) { vis() && renderGraph && page == Page.Debug }
70+
5871
override val assumeJesus by c.setting("Assume Jesus", false) { vis() && page == Page.Misc }
5972
}

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

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,18 @@
1717

1818
package com.lambda.pathing.dstar
1919

20+
import com.lambda.graphics.gl.Matrices
21+
import com.lambda.graphics.gl.Matrices.buildWorldProjection
22+
import com.lambda.graphics.gl.Matrices.withVertexTransform
23+
import com.lambda.graphics.renderer.gui.FontRenderer
24+
import com.lambda.graphics.renderer.gui.FontRenderer.drawString
25+
import com.lambda.pathing.PathingSettings
26+
import com.lambda.util.math.Vec2d
27+
import com.lambda.util.math.div
28+
import com.lambda.util.math.plus
2029
import com.lambda.util.world.FastVector
30+
import com.lambda.util.world.string
31+
import com.lambda.util.world.toCenterVec3d
2132
import kotlin.math.min
2233

2334
/**
@@ -106,6 +117,17 @@ class DStarLite(
106117
}
107118
}
108119

120+
fun updateGraph() {
121+
graph.dirtyNodes.forEach { u ->
122+
if (u != goal) {
123+
gMap.remove(u)
124+
rhsMap.remove(u)
125+
}
126+
updateVertex(u)
127+
}
128+
graph.dirtyNodes.clear()
129+
}
130+
109131
/**
110132
* Propagates changes until the start is locally consistent.
111133
* computeShortestPath():
@@ -115,7 +137,10 @@ class DStarLite(
115137
fun computeShortestPath(cutoffTimeout: Long = 500L) {
116138
val startTime = System.currentTimeMillis()
117139

118-
while ((U.topKey() < calculateKey(start)) || (g(start) < rhs(start)) && (System.currentTimeMillis() - startTime) < cutoffTimeout) {
140+
fun timedOut() = (System.currentTimeMillis() - startTime) > cutoffTimeout
141+
fun shouldUpdateState() = U.topKey() < calculateKey(start) || g(start) < rhs(start)
142+
143+
while (shouldUpdateState() && !timedOut()) {
119144
val u = U.top() ?: break
120145
val oldKey = U.topKey()
121146
val newKey = calculateKey(u)
@@ -170,37 +195,77 @@ class DStarLite(
170195
* Retrieves a path from start to goal by always choosing the successor
171196
* with the lowest g + cost value. If no path is found, the path stops early.
172197
*/
173-
val path: List<FastVector>
174-
get() {
175-
val path = mutableListOf<FastVector>()
176-
177-
if (!graph.contains(start)) return path.toList()
178-
179-
var current = start
180-
path.add(current)
181-
while (current != goal) {
182-
val successors = graph.successors(current)
183-
if (successors.isEmpty()) break
184-
var bestNext: FastVector? = null
185-
var bestVal = INF
186-
for ((succ, cost) in successors) {
187-
val candidate = g(succ) + cost
188-
if (candidate < bestVal) {
189-
bestVal = candidate
190-
bestNext = succ
191-
}
198+
fun path(maxLength: Int = 10_000): List<FastVector> {
199+
val path = mutableListOf<FastVector>()
200+
201+
if (!graph.contains(start)) return path.toList()
202+
203+
var current = start
204+
path.add(current)
205+
while (current != goal) {
206+
val successors = graph.successors(current)
207+
if (successors.isEmpty()) break
208+
var bestNext: FastVector? = null
209+
var bestVal = INF
210+
for ((succ, cost) in successors) {
211+
val candidate = g(succ) + cost
212+
if (candidate < bestVal) {
213+
bestVal = candidate
214+
bestNext = succ
192215
}
193-
// No path
194-
if (bestNext == null) break
195-
current = bestNext
216+
}
217+
// No path
218+
if (bestNext == null) break
219+
current = bestNext
220+
if (current !in path) {
196221
path.add(current)
197-
if (path.size > MAX_PATH_LENGTH) break
222+
} else {
223+
break
198224
}
199-
return path
225+
if (path.size > maxLength) break
200226
}
227+
return path
228+
}
229+
230+
fun buildDebugInfoRenderer(config: PathingSettings) {
231+
if (!config.renderGraph) return
232+
val mode = Matrices.ProjRotationMode.TO_CAMERA
233+
val scale = config.fontScale
234+
graph.nodes.take(config.maxRenderObjects).forEach { origin ->
235+
val label = mutableListOf<String>()
236+
if (config.renderPositions) label.add(origin.string)
237+
if (config.renderG) label.add("g: %.3f".format(g(origin)))
238+
if (config.renderRHS) label.add("rhs: %.3f".format(rhs(origin)))
239+
240+
if (label.isNotEmpty()) {
241+
val pos = origin.toCenterVec3d()
242+
val projection = buildWorldProjection(pos, scale, mode)
243+
withVertexTransform(projection) {
244+
var height = -0.5 * label.size * (FontRenderer.getHeight() + 2)
245+
246+
label.forEach {
247+
drawString(it, Vec2d(-FontRenderer.getWidth(it) * 0.5, height))
248+
height += FontRenderer.getHeight() + 2
249+
}
250+
}
251+
}
252+
253+
if (config.renderCost) {
254+
graph.successors[origin]?.forEach { (neighbor, cost) ->
255+
val centerO = origin.toCenterVec3d()
256+
val centerN = neighbor.toCenterVec3d()
257+
val center = (centerO + centerN) / 2.0
258+
val projection = buildWorldProjection(center, scale, mode)
259+
withVertexTransform(projection) {
260+
val msg = "c: %.3f".format(cost)
261+
drawString(msg, Vec2d(-FontRenderer.getWidth(msg) * 0.5, 0.0))
262+
}
263+
}
264+
}
265+
}
266+
}
201267

202268
companion object {
203269
private const val INF = Double.POSITIVE_INFINITY
204-
private const val MAX_PATH_LENGTH = 100_000
205270
}
206271
}

0 commit comments

Comments
 (0)