Skip to content

Commit 9602e3f

Browse files
committed
Added pathfinder
1 parent 5bfeab0 commit 9602e3f

File tree

15 files changed

+653
-285
lines changed

15 files changed

+653
-285
lines changed

common/src/main/kotlin/com/lambda/graphics/renderer/esp/builders/StaticESPBuilders.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.lambda.util.extension.min
2727
import net.minecraft.block.BlockState
2828
import net.minecraft.util.math.BlockPos
2929
import net.minecraft.util.math.Box
30+
import net.minecraft.util.math.Vec3d
3031
import net.minecraft.util.shape.VoxelShape
3132
import java.awt.Color
3233

@@ -225,3 +226,15 @@ fun StaticESPRenderer.buildOutline(
225226

226227
updateOutlines = true
227228
}
229+
230+
fun StaticESPRenderer.buildLine(
231+
start: Vec3d,
232+
end: Vec3d,
233+
color: Color,
234+
) = outlines.use {
235+
val vertex1 by vertex(outlineVertices, start.x, start.y, start.z, color)
236+
val vertex2 by vertex(outlineVertices, end.x, end.y, end.z, color)
237+
putLine(vertex1, vertex2)
238+
239+
updateOutlines = true
240+
}

common/src/main/kotlin/com/lambda/interaction/construction/simulation/Simulation.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ import com.lambda.module.modules.client.TaskFlowModule
3030
import com.lambda.threading.runSafe
3131
import com.lambda.util.BlockUtils.blockState
3232
import com.lambda.util.world.FastVector
33+
import com.lambda.util.world.WorldUtils.playerFitsIn
34+
import com.lambda.util.world.WorldUtils.traversable
3335
import com.lambda.util.world.toBlockPos
3436
import com.lambda.util.world.toVec3d
3537
import net.minecraft.client.network.ClientPlayerEntity
3638
import net.minecraft.util.math.BlockPos
3739
import net.minecraft.util.math.Box
38-
import net.minecraft.util.math.Direction
3940
import net.minecraft.util.math.Vec3d
4041
import java.awt.Color
4142

@@ -57,10 +58,7 @@ data class Simulation(
5758
val isTooFar = blueprint.getClosestPointTo(view).distanceTo(view) > 10.0
5859
runSafe {
5960
if (isOutOfBounds && isTooFar) return@getOrPut emptySet()
60-
val blockPos = pos.toBlockPos()
61-
val isWalkable = blockState(blockPos.down()).isSideSolidFullSquare(world, blockPos, Direction.UP)
62-
if (!isWalkable) return@getOrPut emptySet()
63-
if (!playerFitsIn(blockPos)) return@getOrPut emptySet()
61+
if (!traversable(pos.toBlockPos())) return@getOrPut emptySet()
6462
}
6563

6664
blueprint.simulate(view, interact, rotation, inventory, build)
@@ -74,10 +72,6 @@ data class Simulation(
7472
}
7573
}
7674

77-
private fun SafeContext.playerFitsIn(pos: BlockPos): Boolean {
78-
return world.isSpaceEmpty(Vec3d.ofBottomCenter(pos).playerBox())
79-
}
80-
8175
companion object {
8276
fun Vec3d.playerBox(): Box = Box(x - 0.3, y, z - 0.3, x + 0.3, y + 1.8, z + 0.3).contract(1.0E-6)
8377

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2025 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.modules.movement
19+
20+
import com.lambda.event.events.RenderEvent
21+
import com.lambda.event.listener.SafeListener.Companion.listen
22+
import com.lambda.graphics.renderer.esp.builders.buildLine
23+
import com.lambda.module.Module
24+
import com.lambda.module.modules.client.TaskFlowModule.drawables
25+
import com.lambda.module.tag.ModuleTag
26+
import com.lambda.pathing.AStar
27+
import com.lambda.pathing.AStar.findPathAStar
28+
import com.lambda.pathing.goal.SimpleGoal
29+
import com.lambda.util.math.setAlpha
30+
import com.lambda.util.world.fastVectorOf
31+
import com.lambda.util.world.toBlockPos
32+
import com.lambda.util.world.toFastVec
33+
import com.lambda.util.world.toVec3d
34+
import java.awt.Color
35+
36+
object Pathfinder : Module(
37+
name = "Pathfinder",
38+
description = "Get from A to B",
39+
defaultTags = setOf(ModuleTag.MOVEMENT)
40+
) {
41+
init {
42+
listen<RenderEvent.StaticESP> {
43+
val path = findPathAStar(player.blockPos.toFastVec(), SimpleGoal(fastVectorOf(0, 120, 0)))
44+
45+
path.nodes.zipWithNext { current, next ->
46+
val currentPos = current.pos.toBlockPos().toCenterPos()
47+
val nextPos = next.pos.toBlockPos().toCenterPos()
48+
it.renderer.buildLine(currentPos, nextPos, Color.BLUE.setAlpha(0.25))
49+
}
50+
}
51+
}
52+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2025 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.pathing
19+
20+
import com.lambda.context.SafeContext
21+
import com.lambda.pathing.Node.Companion.toNode
22+
import com.lambda.pathing.goal.Goal
23+
import com.lambda.pathing.move.Move
24+
import com.lambda.util.world.FastVector
25+
import com.lambda.util.world.WorldUtils.traversable
26+
import com.lambda.util.world.toBlockPos
27+
import java.util.PriorityQueue
28+
29+
object AStar {
30+
fun SafeContext.findPathAStar(start: FastVector, goal: Goal): Path {
31+
val openSet = PriorityQueue<Node>()
32+
val closedSet = mutableSetOf<Node>()
33+
val startNode = start.toNode(goal)
34+
startNode.gCost = 0.0
35+
openSet.add(startNode)
36+
37+
while (openSet.isNotEmpty()) {
38+
val current = openSet.remove()
39+
if (goal.inGoal(current.pos)) {
40+
// println("Not yet considered nodes: ${openSet.size}")
41+
// println("Closed nodes: ${closedSet.size}")
42+
return current.createPathToSource()
43+
}
44+
45+
closedSet.add(current)
46+
47+
moveOptions(current.pos).forEach { move ->
48+
val successor = move.node(current.pos, goal)
49+
if (closedSet.contains(successor)) return@forEach
50+
val tentativeGCost = current.gCost + move.cost()
51+
if (tentativeGCost >= successor.gCost) return@forEach
52+
successor.predecessor = current
53+
successor.gCost = tentativeGCost
54+
openSet.add(successor)
55+
}
56+
}
57+
58+
println("No path found")
59+
return Path()
60+
}
61+
62+
private fun SafeContext.moveOptions(origin: FastVector): List<Move> {
63+
val originPos = origin.toBlockPos()
64+
return Move.entries.filter { move ->
65+
traversable(originPos.add(move.x, move.y, move.z))
66+
}
67+
}
68+
69+
// class Move(
70+
// private val origin: FastVector,
71+
// val offset: FastVector,
72+
// ) {
73+
// val cost: Double = origin.distManhattan(offset).toDouble()
74+
//
75+
// fun nextNode(goal: Goal) =
76+
// origin.plus(offset).toNode(goal)
77+
// }
78+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2025 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.pathing
19+
20+
import com.lambda.pathing.goal.Goal
21+
import com.lambda.util.world.FastVector
22+
import com.lambda.util.world.toBlockPos
23+
24+
data class Node(
25+
val pos: FastVector,
26+
var predecessor: Node? = null,
27+
var gCost: Double = Double.POSITIVE_INFINITY,
28+
val hCost: Double
29+
) : Comparable<Node> {
30+
// use updateable lazy and recompute on gCost change
31+
private val fCost get() = gCost + hCost
32+
33+
override fun compareTo(other: Node) =
34+
fCost.compareTo(other.fCost)
35+
36+
fun createPathToSource(): Path {
37+
val path = Path()
38+
var current: Node? = this
39+
while (current != null) {
40+
path.prepend(current)
41+
current = current.predecessor
42+
}
43+
return path
44+
}
45+
46+
override fun toString() = "Node(pos=${pos.toBlockPos().toShortString()}, gCost=$gCost, hCost=$hCost)"
47+
48+
companion object {
49+
fun FastVector.toNode(goal: Goal) =
50+
Node(this, hCost = goal.heuristic(this))
51+
}
52+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2025 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.pathing
19+
20+
import com.lambda.util.world.toBlockPos
21+
22+
data class Path(
23+
val nodes: ArrayDeque<Node> = ArrayDeque(),
24+
) {
25+
fun prepend(node: Node) {
26+
nodes.addFirst(node)
27+
}
28+
29+
override fun toString() =
30+
nodes.joinToString(" -> ") { "(${it.pos.toBlockPos().toShortString()})" }
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2025 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.pathing.goal
19+
20+
import com.lambda.util.world.FastVector
21+
22+
interface Goal {
23+
fun inGoal(pos: FastVector): Boolean
24+
25+
fun heuristic(pos: FastVector): Double
26+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2025 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.pathing.goal
19+
20+
import com.lambda.util.world.FastVector
21+
import com.lambda.util.world.distSq
22+
23+
class SimpleGoal(
24+
val pos: FastVector,
25+
) : Goal {
26+
override fun inGoal(pos: FastVector) = pos == this.pos
27+
28+
override fun heuristic(pos: FastVector) = pos distSq this.pos
29+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2025 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.pathing.move
19+
20+
import com.lambda.pathing.Node
21+
import com.lambda.pathing.Node.Companion.toNode
22+
import com.lambda.pathing.goal.Goal
23+
import com.lambda.util.world.FastVector
24+
import com.lambda.util.world.offset
25+
import kotlin.math.abs
26+
27+
enum class Move(val x: Int, val y: Int, val z: Int) {
28+
TRAVERSE_NORTH(0, 0, -1),
29+
TRAVERSE_NORTH_EAST(1, 0, -1),
30+
TRAVERSE_EAST(1, 0, 0),
31+
TRAVERSE_SOUTH_EAST(1, 0, 1),
32+
TRAVERSE_SOUTH(0, 0, 1),
33+
TRAVERSE_SOUTH_WEST(-1, 0, 1),
34+
TRAVERSE_WEST(-1, 0, 0),
35+
TRAVERSE_NORTH_WEST(-1, 0, -1),
36+
PILLAR(0, 1, 0),
37+
ASCEND_NORTH(0, 1, -1),
38+
ASCEND_EAST(1, 1, 0),
39+
ASCEND_SOUTH(0, 1, 1),
40+
ASCEND_WEST(-1, 1, 0),
41+
FALL(0, -1, 0),
42+
DESCEND_NORTH(0, -1, -1),
43+
DESCEND_EAST(1, -1, 0),
44+
DESCEND_SOUTH(0, -1, 1),
45+
DESCEND_WEST(-1, -1, 0);
46+
47+
fun cost(): Int = abs(x) + abs(y) + abs(z)
48+
49+
// ToDo: Use DirectionMask
50+
fun node(origin: FastVector, goal: Goal): Node = origin.offset(x, y, z).toNode(goal)
51+
}

0 commit comments

Comments
 (0)