Skip to content

Commit 44c64ec

Browse files
committed
Incremental pathfinding with updateable weights
1 parent cc433cb commit 44c64ec

File tree

14 files changed

+1199
-353
lines changed

14 files changed

+1199
-353
lines changed

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

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.lambda.command.commands
1919

20+
import com.lambda.brigadier.argument.double
2021
import com.lambda.brigadier.argument.integer
2122
import com.lambda.brigadier.argument.literal
2223
import com.lambda.brigadier.argument.value
@@ -30,36 +31,130 @@ import com.lambda.util.world.fastVectorOf
3031
import com.lambda.util.world.string
3132

3233
object PathCommand : LambdaCommand(
33-
name = "path",
34+
name = "pathfinder",
3435
usage = "path <invalidate | reset | update>",
35-
description = "Move through world"
36+
description = "Finds a quick path through the world",
37+
aliases = setOf("path")
3638
) {
3739
override fun CommandBuilder.create() {
40+
required(literal("target")) {
41+
required(integer("X", -30000000, 30000000)) { x ->
42+
required(integer("Y", -64, 255)) { y ->
43+
required(integer("Z", -30000000, 30000000)) { z ->
44+
execute {
45+
val v = fastVectorOf(x().value(), y().value(), z().value())
46+
Pathfinder.target = v
47+
this@PathCommand.info("Set new target at ${v.string}")
48+
}
49+
}
50+
}
51+
}
52+
}
53+
3854
required(literal("invalidate")) {
3955
required(integer("X", -30000000, 30000000)) { x ->
4056
required(integer("Y", -64, 255)) { y ->
4157
required(integer("Z", -30000000, 30000000)) { z ->
4258
execute {
43-
val dirty = fastVectorOf(x().value(), y().value(), z().value())
44-
Pathfinder.dStar.invalidate(dirty)
45-
this@PathCommand.info("Invalidated ${dirty.string}")
59+
val v = fastVectorOf(x().value(), y().value(), z().value())
60+
Pathfinder.dStar.invalidate(v)
61+
this@PathCommand.info("Invalidated ${v.string}")
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
required(literal("remove")) {
69+
required(integer("X", -30000000, 30000000)) { x ->
70+
required(integer("Y", -64, 255)) { y ->
71+
required(integer("Z", -30000000, 30000000)) { z ->
72+
execute {
73+
val v = fastVectorOf(x().value(), y().value(), z().value())
74+
Pathfinder.graph.remove(v)
75+
this@PathCommand.info("Removed ${v.string}")
76+
}
77+
}
78+
}
79+
}
80+
}
81+
82+
required(literal("update")) {
83+
required(integer("X", -30000000, 30000000)) { x ->
84+
required(integer("Y", -64, 255)) { y ->
85+
required(integer("Z", -30000000, 30000000)) { z ->
86+
execute {
87+
val u = fastVectorOf(x().value(), y().value(), z().value())
88+
Pathfinder.dStar.updateVertex(u)
89+
this@PathCommand.info("Updated ${u.string}")
4690
}
4791
}
4892
}
4993
}
5094
}
5195

52-
required(literal("reset")) {
96+
required(literal("successor")) {
97+
required(integer("X", -30000000, 30000000)) { x ->
98+
required(integer("Y", -64, 255)) { y ->
99+
required(integer("Z", -30000000, 30000000)) { z ->
100+
execute {
101+
val v = fastVectorOf(x().value(), y().value(), z().value())
102+
this@PathCommand.info("Successors: ${Pathfinder.graph.successors[v]?.keys?.joinToString { it.string }}")
103+
}
104+
}
105+
}
106+
}
107+
}
108+
109+
required(literal("predecessors")) {
110+
required(integer("X", -30000000, 30000000)) { x ->
111+
required(integer("Y", -64, 255)) { y ->
112+
required(integer("Z", -30000000, 30000000)) { z ->
113+
execute {
114+
val v = fastVectorOf(x().value(), y().value(), z().value())
115+
this@PathCommand.info("Predecessors: ${Pathfinder.graph.predecessors[v]?.keys?.joinToString { it.string }}")
116+
}
117+
}
118+
}
119+
}
120+
}
121+
122+
required(literal("setEdge")) {
123+
required(integer("X1", -30000000, 30000000)) { x1 ->
124+
required(integer("Y1", -64, 255)) { y1 ->
125+
required(integer("Z1", -30000000, 30000000)) { z1 ->
126+
required(integer("X2", -30000000, 30000000)) { x2 ->
127+
required(integer("Y2", -64, 255)) { y2 ->
128+
required(integer("Z2", -30000000, 30000000)) { z2 ->
129+
required(double("cost")) { cost ->
130+
execute {
131+
val v1 = fastVectorOf(x1().value(), y1().value(), z1().value())
132+
val v2 = fastVectorOf(x2().value(), y2().value(), z2().value())
133+
val c = cost().value()
134+
Pathfinder.dStar.updateEdge(v1, v2, c)
135+
Pathfinder.needsUpdate = true
136+
this@PathCommand.info("Updated edge ${v1.string} -> ${v2.string} to cost of $c")
137+
}
138+
}
139+
}
140+
}
141+
}
142+
}
143+
}
144+
}
145+
}
146+
147+
required(literal("clear")) {
53148
execute {
54149
Pathfinder.graph.clear()
55-
this@PathCommand.info("Reset graph")
150+
this@PathCommand.info("Cleared graph")
56151
}
57152
}
58153

59-
required(literal("update")) {
154+
required(literal("refresh")) {
60155
execute {
61156
Pathfinder.needsUpdate = true
62-
this@PathCommand.info("Marked graph for update")
157+
this@PathCommand.info("Marked pathfinder for refresh")
63158
}
64159
}
65160
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2024 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.hud
19+
20+
import com.lambda.module.HudModule
21+
import com.lambda.module.modules.movement.Pathfinder
22+
import com.lambda.module.tag.ModuleTag
23+
24+
object PathfinderHUD : HudModule.Text(
25+
name = "PathfinderHUD",
26+
defaultTags = setOf(ModuleTag.CLIENT),
27+
) {
28+
override fun getText() = Pathfinder.debugInfo()
29+
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import com.lambda.util.world.FastVector
5353
import com.lambda.util.world.WorldUtils.hasSupport
5454
import com.lambda.util.world.dist
5555
import com.lambda.util.world.fastVectorOf
56+
import com.lambda.util.world.string
5657
import com.lambda.util.world.toBlockPos
5758
import com.lambda.util.world.toFastVec
5859
import com.lambda.util.world.x
@@ -73,10 +74,9 @@ object Pathfinder : Module(
7374
description = "Get from A to B",
7475
defaultTags = setOf(ModuleTag.MOVEMENT)
7576
) {
76-
private val targetPos by setting("Target", BlockPos(0, 78, 0))
7777
private val pathing = PathingSettings(this)
7878

79-
private val target: FastVector get() = targetPos.toFastVec()
79+
var target = fastVectorOf(0, 78, 0)
8080
val graph = LazyGraph { origin ->
8181
runSafe {
8282
moveOptions(origin, ::heuristic, pathing).associate { it.pos to it.cost }
@@ -269,4 +269,12 @@ object Pathfinder : Module(
269269
.add(integralError.multiply(pathing.kI))
270270
.add(derivativeError.multiply(pathing.kD))
271271
}
272+
273+
fun debugInfo() = buildString {
274+
appendLine("Current Start: ${currentStart.string}")
275+
appendLine("Current Target: ${currentTarget?.string}")
276+
appendLine("Path Length: ${coarsePath.length().string} Nodes: ${coarsePath.size}")
277+
if (pathing.refinePath) appendLine("Refined Path: ${refinedPath.length().string} Nodes: ${refinedPath.size}")
278+
if (pathing.algorithm == PathingConfig.PathingAlgorithm.D_STAR_LITE) append(dStar.toString())
279+
}
272280
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,14 @@ interface PathingConfig {
5252
val renderRefinedPath: Boolean
5353
val renderGoal: Boolean
5454
val renderGraph: Boolean
55+
val renderSuccessors: Boolean
56+
val renderPredecessors: Boolean
57+
val renderInvalidated: Boolean
5558
val renderPositions: Boolean
5659
val renderCost: Boolean
5760
val renderG: Boolean
5861
val renderRHS: Boolean
62+
val renderKey: Boolean
5963
val maxRenderObjects: Int
6064
val fontScale: Double
6165
val assumeJesus: Boolean

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,14 @@ class PathingSettings(
6161
override val renderRefinedPath by c.setting("Render Refined Path", true) { vis() && page == Page.Debug }
6262
override val renderGoal by c.setting("Render Goal", true) { vis() && page == Page.Debug }
6363
override val renderGraph by c.setting("Render Graph", false) { vis() && page == Page.Debug }
64+
override val renderSuccessors by c.setting("Render Successors", false) { vis() && page == Page.Debug && renderGraph }
65+
override val renderPredecessors by c.setting("Render Predecessors", false) { vis() && page == Page.Debug && renderGraph }
66+
override val renderInvalidated by c.setting("Render Invalidated", false) { vis() && page == Page.Debug && renderGraph }
6467
override val renderPositions by c.setting("Render Positions", false) { vis() && page == Page.Debug && renderGraph }
6568
override val renderCost by c.setting("Render Cost", false) { vis() && page == Page.Debug && renderGraph }
6669
override val renderG by c.setting("Render G", false) { vis() && page == Page.Debug && renderGraph }
6770
override val renderRHS by c.setting("Render RHS", false) { vis() && page == Page.Debug && renderGraph }
71+
override val renderKey by c.setting("Render Key", false) { vis() && page == Page.Debug && renderGraph }
6872
override val maxRenderObjects by c.setting("Max Render Objects", 1000, 0..10_000, 100) { vis() && page == Page.Debug && renderGraph }
6973
override val fontScale by c.setting("Font Scale", 0.4, 0.0..2.0, 0.01) { vis() && renderGraph && page == Page.Debug }
7074

0 commit comments

Comments
 (0)