Skip to content

Commit c0c63e7

Browse files
committed
Speed up clearance checks
1 parent 2d2bd55 commit c0c63e7

File tree

8 files changed

+58
-56
lines changed

8 files changed

+58
-56
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,13 @@ import com.lambda.interaction.construction.simulation.BuildSimulator.simulate
2828
import com.lambda.interaction.request.rotation.RotationConfig
2929
import com.lambda.module.modules.client.TaskFlowModule
3030
import com.lambda.threading.runSafe
31-
import com.lambda.util.BlockUtils.blockState
3231
import com.lambda.util.world.FastVector
3332
import com.lambda.util.world.WorldUtils.playerBox
34-
import com.lambda.util.world.WorldUtils.playerFitsIn
3533
import com.lambda.util.world.WorldUtils.traversable
3634
import com.lambda.util.world.toBlockPos
3735
import com.lambda.util.world.toVec3d
3836
import net.minecraft.client.network.ClientPlayerEntity
3937
import net.minecraft.util.math.BlockPos
40-
import net.minecraft.util.math.Box
4138
import net.minecraft.util.math.Vec3d
4239
import java.awt.Color
4340

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,6 @@ object Pathfinder : Module(
136136
}
137137
}
138138

139-
private fun Path.render(renderer: StaticESP, color: Color) {
140-
moves.zipWithNext { current, next ->
141-
val currentPos = current.pos.toBlockPos().toCenterPos()
142-
val nextPos = next.pos.toBlockPos().toCenterPos()
143-
renderer.buildLine(currentPos, nextPos, color)
144-
}
145-
}
146-
147139
private fun SafeContext.updateTargetNode() {
148140
shortPath.moves.firstOrNull()?.let { current ->
149141
if (player.pos.distanceTo(current.bottomPos) < pathing.tolerance) {
@@ -171,7 +163,7 @@ object Pathfinder : Module(
171163
val thetaStar = measureTimeMillis {
172164
short = thetaStarClearance(long, pathing)
173165
}
174-
info("A* (Length: ${long.length.string} Nodes: ${long.moves.size} T: $aStar ms) and Theta* (Length: ${short.length.string} Nodes: ${short.moves.size} T: $thetaStar ms)")
166+
info("A* (Length: ${long.length().string} Nodes: ${long.moves.size} T: $aStar ms) and Theta* (Length: ${short.length().string} Nodes: ${short.moves.size} T: $thetaStar ms)")
175167
println("Long: $long | Short: $short")
176168
short.moves.removeFirstOrNull()
177169
longPath = long

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,40 @@
1717

1818
package com.lambda.pathing
1919

20+
import com.lambda.graphics.renderer.esp.builders.buildLine
21+
import com.lambda.graphics.renderer.esp.global.StaticESP
2022
import com.lambda.pathing.move.Move
23+
import com.lambda.util.collections.updatableLazy
2124
import com.lambda.util.world.dist
2225
import com.lambda.util.world.toBlockPos
26+
import java.awt.Color
2327

2428
data class Path(
2529
val moves: ArrayDeque<Move> = ArrayDeque(),
2630
) {
2731
fun append(move: Move) {
2832
moves.addLast(move)
33+
length.clear()
2934
}
3035

3136
fun prepend(move: Move) {
3237
moves.addFirst(move)
38+
length.clear()
3339
}
3440

35-
val length get() = moves.zipWithNext { a, b -> a.pos dist b.pos }.sum()
41+
private val length = updatableLazy {
42+
moves.zipWithNext { a, b -> a.pos dist b.pos }.sum()
43+
}
44+
45+
fun render(renderer: StaticESP, color: Color) {
46+
moves.zipWithNext { current, next ->
47+
val currentPos = current.pos.toBlockPos().toCenterPos()
48+
val nextPos = next.pos.toBlockPos().toCenterPos()
49+
renderer.buildLine(currentPos, nextPos, color)
50+
}
51+
}
52+
53+
fun length() = length.value
3654

3755
override fun toString() =
3856
moves.joinToString(" -> ") { "(${it.pos.toBlockPos().toShortString()})" }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class DStarLite(
189189
if (bestNext == null) break
190190
current = bestNext
191191
path.add(current)
192-
if (path.size > 100000) break
192+
if (path.size > 100_000) break
193193
}
194194
return path
195195
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class PriorityQueueDStar {
2828
private val pq = PriorityQueue<Pair<FastVector, Key>>(compareBy { it.second })
2929
private val vertexToKey = mutableMapOf<FastVector, Key>()
3030

31-
fun isEmpty(): Boolean = pq.isEmpty()
31+
fun isEmpty() = pq.isEmpty()
3232

3333
fun topKey(): Key {
3434
return if (pq.isEmpty()) Key(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)

common/src/main/kotlin/com/lambda/pathing/move/MoveFinder.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ import com.lambda.pathing.goal.Goal
2323
import com.lambda.util.BlockUtils.blockState
2424
import com.lambda.util.BlockUtils.fluidState
2525
import com.lambda.util.world.FastVector
26-
import com.lambda.util.world.WorldUtils.hasSupport
27-
import com.lambda.util.world.WorldUtils.isPathClear
26+
import com.lambda.util.world.WorldUtils.traversable
2827
import com.lambda.util.world.add
2928
import com.lambda.util.world.fastVectorOf
3029
import com.lambda.util.world.length
31-
import com.lambda.util.world.offset
3230
import com.lambda.util.world.toBlockPos
3331
import net.minecraft.block.BlockState
3432
import net.minecraft.block.Blocks
@@ -45,27 +43,30 @@ import net.minecraft.item.Items
4543
import net.minecraft.registry.tag.BlockTags
4644
import net.minecraft.registry.tag.FluidTags
4745
import net.minecraft.util.math.BlockPos
46+
import net.minecraft.util.math.Box
4847
import net.minecraft.util.math.Direction
4948
import net.minecraft.util.math.EightWayDirection
49+
import kotlin.reflect.KFunction1
5050

5151
object MoveFinder {
5252
private val nodeTypeCache = HashMap<FastVector, NodeType>()
5353

5454
fun SafeContext.moveOptions(origin: Move, goal: Goal, config: PathingConfig) =
5555
EightWayDirection.entries.flatMap { direction ->
5656
(-1..1).mapNotNull { y ->
57-
getPathNode(goal, origin, direction, y, config)
57+
getPathNode(goal::heuristic, origin, direction, y, config)
5858
}
5959
}
6060

6161
private fun SafeContext.getPathNode(
62-
goal: Goal,
62+
heuristic: KFunction1<FastVector, Double>,
6363
origin: Move,
6464
direction: EightWayDirection,
6565
height: Int,
6666
config: PathingConfig
6767
): Move? {
6868
val offset = fastVectorOf(direction.offsetX, height, direction.offsetZ)
69+
val diagonal = direction.ordinal.mod(2) == 1
6970
val checkingPos = origin.pos.add(offset)
7071
val checkingBlockPos = checkingPos.toBlockPos()
7172
val originBlockPos = origin.pos.toBlockPos()
@@ -74,20 +75,19 @@ object MoveFinder {
7475
val nodeType = findPathType(checkingPos)
7576
if (nodeType == NodeType.BLOCKED) return null
7677

77-
val clear = when {
78-
height == 0 -> isPathClear(originBlockPos, checkingBlockPos, config.clearancePrecition)
79-
height > 0 -> {
80-
val between = origin.pos.offset(0, height, 0)
81-
isPathClear(origin.pos, between, config.clearancePrecition, false) && isPathClear(between, checkingPos, config.clearancePrecition, false) && hasSupport(checkingBlockPos)
82-
}
83-
else -> {
84-
val between = origin.pos.offset(direction.offsetX, 0, direction.offsetZ)
85-
isPathClear(origin.pos, between, config.clearancePrecition, false) && isPathClear(between, checkingPos, config.clearancePrecition, false) && hasSupport(checkingBlockPos)
78+
val clear = if (diagonal) {
79+
val enclose = when {
80+
checkingBlockPos.y == originBlockPos.y -> Box.enclosing(originBlockPos.up(), checkingBlockPos)
81+
checkingBlockPos.y < originBlockPos.y -> Box.enclosing(originBlockPos.up(), checkingBlockPos.up())
82+
else -> Box.enclosing(originBlockPos.up(2), checkingBlockPos)
8683
}
84+
traversable(checkingBlockPos) && world.isSpaceEmpty(enclose)
85+
} else {
86+
traversable(checkingBlockPos)
8787
}
8888
if (!clear) return null
8989

90-
val hCost = goal.heuristic(checkingPos) /** nodeType.penalty*/
90+
val hCost = heuristic(checkingPos) /** nodeType.penalty*/
9191
val cost = offset.length()
9292
val currentFeetY = getFeetY(checkingBlockPos)
9393

common/src/main/kotlin/com/lambda/util/collections/UpdatableLazy.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ class UpdatableLazy<T>(private val initializer: () -> T) {
4343
*/
4444
val value: T get() = _value ?: initializer().also { _value = it }
4545

46+
/**
47+
* Clears the currently stored value, setting it to null.
48+
*
49+
* This function is used to explicitly reset the stored value, effectively marking
50+
* it as uninitialized. It can subsequently be re-initialized through lazy evaluation
51+
* when accessed again.
52+
*/
53+
fun clear() {
54+
_value = null
55+
}
56+
4657
/**
4758
* Resets the current value to a new value generated by the initializer function.
4859
*

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

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,14 @@ package com.lambda.util.world
1919

2020
import com.lambda.context.SafeContext
2121
import com.lambda.util.BlockUtils.blockState
22-
import com.lambda.util.math.flooredBlockPos
23-
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
2422
import net.minecraft.util.math.BlockPos
2523
import net.minecraft.util.math.Box
2624
import net.minecraft.util.math.Direction
2725
import net.minecraft.util.math.Vec3d
28-
import kotlin.math.min
2926

3027
object WorldUtils {
3128
fun SafeContext.traversable(pos: BlockPos) =
32-
blockState(pos.down()).isSideSolidFullSquare(world, pos.down(), Direction.UP) && playerFitsIn(pos)
33-
34-
fun SafeContext.isPathClear(
35-
start: FastVector,
36-
end: FastVector,
37-
stepSize: Double = 0.3,
38-
supportCheck: Boolean = true,
39-
) = isPathClear(start.toBlockPos(), end.toBlockPos(), stepSize, supportCheck)
29+
hasSupport(pos) && hasClearance(pos)
4030

4131
fun SafeContext.isPathClear(
4232
start: BlockPos,
@@ -61,34 +51,28 @@ object WorldUtils {
6151
var currentPos = start
6252

6353
(0 until steps).forEach { _ ->
64-
val playerNotFitting = !playerFitsIn(currentPos)
54+
val playerNotFitting = !hasClearance(currentPos)
6555
val hasNoSupport = !hasSupport(currentPos)
6656
if (playerNotFitting || (supportCheck && hasNoSupport)) {
6757
return false
6858
}
6959
currentPos = currentPos.add(stepDirection)
7060
}
7161

72-
return playerFitsIn(end)
62+
return hasClearance(end)
7363
}
7464

75-
fun SafeContext.playerFitsIn(pos: BlockPos) =
76-
playerFitsIn(Vec3d.ofBottomCenter(pos))
77-
78-
fun SafeContext.playerFitsIn(pos: Vec3d) =
65+
private fun SafeContext.hasClearance(pos: Vec3d) =
7966
world.isSpaceEmpty(player, pos.playerBox().contract(1.0E-6))
8067

81-
fun SafeContext.hasSupport(pos: BlockPos) =
82-
hasSupport(Vec3d.ofBottomCenter(pos))
83-
84-
// private fun SafeContext.hasSupport(pos: BlockPos) =
85-
// blockState(pos.down()).isSideSolidFullSquare(world, pos.down(), Direction.UP)
86-
8768
fun SafeContext.hasSupport(pos: Vec3d) =
88-
!world.isSpaceEmpty(player, pos.playerBox().expand(1.0E-6))
69+
!world.isSpaceEmpty(player, pos.playerBox().expand(1.0E-6).contract(0.05, 0.0, 0.05))
70+
71+
private fun SafeContext.hasClearance(pos: BlockPos) =
72+
blockState(pos).isAir && blockState(pos.up()).isAir
8973

90-
// fun SafeContext.hasSupport(pos: Vec3d) =
91-
// world.canCollide(null, pos.playerBox().expand(1.0E-6))
74+
private fun SafeContext.hasSupport(pos: BlockPos) =
75+
blockState(pos.down()).isSideSolidFullSquare(world, pos.down(), Direction.UP)
9276

9377
fun Vec3d.playerBox(): Box =
9478
Box(x - 0.3, y, z - 0.3, x + 0.3, y + 1.8, z + 0.3)

0 commit comments

Comments
 (0)