1717
1818package com.lambda.module.modules.movement
1919
20+ import baritone.api.pathing.goals.GoalGetToBlock
2021import com.lambda.config.AutomationConfig.Companion.setDefaultAutomationConfig
2122import com.lambda.config.applyEdits
2223import com.lambda.context.SafeContext
@@ -25,7 +26,9 @@ import com.lambda.event.events.MovementEvent
2526import com.lambda.event.events.PacketEvent
2627import com.lambda.event.events.TickEvent
2728import com.lambda.event.listener.SafeListener.Companion.listen
29+ import com.lambda.interaction.BaritoneManager
2830import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest
31+ import com.lambda.interaction.material.StackSelection.Companion.select
2932import com.lambda.module.Module
3033import com.lambda.module.modules.movement.BetterFirework.canOpenElytra
3134import com.lambda.module.modules.movement.BetterFirework.canTakeoff
@@ -35,12 +38,18 @@ import com.lambda.threading.runSafe
3538import com.lambda.util.Timer
3639import com.lambda.util.extension.isElytraFlying
3740import com.lambda.util.player.MovementUtils.addSpeed
38- import com.lambda.util.player.SlotUtils.hotbarAndInventoryStacks
3941import com.lambda.util.player.SlotUtils.hotbarStacks
4042import com.lambda.util.player.hasFirework
41- import com.lambda.interaction.material.StackSelection.Companion.selectStack
4243import com.lambda.module.hud.Speedometer
44+ import com.lambda.util.BlockUtils.blockState
4345import com.lambda.util.SpeedUnit
46+ import com.lambda.util.math.dist
47+ import com.lambda.util.math.flooredBlockPos
48+ import com.lambda.util.math.isLoaded
49+ import com.lambda.util.player.SlotUtils.inventoryStacks
50+ import com.lambda.util.world.raycast.InteractionMask
51+ import com.lambda.util.world.raycast.RayCastUtils.blockResult
52+ import com.lambda.util.world.raycast.RayCastUtils.rayCast
4453import net.minecraft.component.DataComponentTypes
4554import net.minecraft.entity.Entity
4655import net.minecraft.item.ItemStack
@@ -49,6 +58,13 @@ import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
4958import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket
5059import net.minecraft.sound.SoundEvents
5160import net.minecraft.util.math.Vec3d
61+ import java.lang.Math.toDegrees
62+ import java.lang.Math.toRadians
63+ import kotlin.math.atan2
64+ import kotlin.math.cos
65+ import kotlin.math.hypot
66+ import kotlin.math.roundToInt
67+ import kotlin.math.sin
5268import kotlin.time.Duration.Companion.seconds
5369
5470object ElytraFly : Module(
@@ -57,35 +73,42 @@ object ElytraFly : Module(
5773 tag = ModuleTag .MOVEMENT ,
5874) {
5975 @JvmStatic val mode by setting(" Mode" , FlyMode .Bounce )
76+
6077 private val inventory by setting(" Inventory" , true , " Allow using fireworks from the players inventory" ) { mode == FlyMode .GrimControl }
6178
6279 // ToDo: Implement these commented out settings
6380 private val takeoff by setting(" Takeoff" , true , " Automatically jumps and initiates gliding" ) { mode == FlyMode .Bounce }
6481 private val autoPitch by setting(" Auto Pitch" , true , " Automatically pitches the players rotation down to bounce at faster speeds" ) { mode == FlyMode .Bounce }
65- private val pitch by setting(" Pitch" , 80 , 0 .. 90 , 1 ) { autoPitch && mode == FlyMode .Bounce }
82+ private val pitch by setting(" Pitch" , 80 , 0 .. 90 , 1 ) { mode == FlyMode .Bounce && autoPitch }
6683 private val yMotion by setting(" Y Motion" , false , " Cancels the players y velocity to aid speed" ) { mode == FlyMode .Bounce }
67- private val yMotionStartSpeed by setting(" Y Motion Start Speed" , 30 , 5 .. 30 , 1 , " bps" ) { mode == FlyMode .Bounce && yMotion }
68- private val speedLimit by setting(" Speed Limit" , 110 , 10 .. 720 , 1 , " bps" ) { mode == FlyMode .Bounce && yMotion }
84+ private val yMotionStartSpeed by setting(" Y Motion Start Speed" , 30 , 5 .. 40 , 1 , " bps" ) { mode == FlyMode .Bounce && yMotion }
85+ private val speedLimit by setting(" Speed Limit" , 110 , 10 .. 400 , 1 , " bps" ) { mode == FlyMode .Bounce && yMotion }
6986 private val jump by setting(" Jump" , true , " Automatically jumps" ) { mode == FlyMode .Bounce }
70- private val flagPause by setting(" Flag Pause" , 20 , 0 .. 100 , 1 , " How long to pause if the server flags you for a movement check" ) { mode == FlyMode .Bounce }
71- // private val passObstacles by setting("Pass Obstacles", true, "Automatically paths around obstacles using baritone") { mode == FlyMode.Bounce }
87+ private val flagPause by setting(" Flag Pause" , 5 , 0 .. 100 , 1 , " How long to pause if the server flags you for a movement check" , " ticks" ) { mode == FlyMode .Bounce }
88+ private val passObstacles by setting(" Pass Obstacles" , true , " Automatically paths around obstacles using baritone" ) { mode == FlyMode .Bounce }
89+ private val acceptableOffsetRange by setting(" Acceptable Offset Range" , 2.0 , 0.1 .. 5.0 , 0.01 , " Acceptable offset from the original flight line to allow when starting to fly again after passing obstacles" ) { mode == FlyMode .Bounce && passObstacles }
90+ private val obstacleLookAhead by setting(" Obstacle Look-Ahead" , 15 , 0 .. 50 , 1 , " Looks ahead of the player to see if obstacles are in the way" ) { mode == FlyMode .Bounce && passObstacles }
91+ private val directionStep by setting(" Direction Step" , 45.0 , 0.0 .. 180.0 , 0.1 , " The step size to use when locking the flight direction" ) { mode == FlyMode .Bounce && passObstacles }
7292
7393 private val boostSpeed by setting(" Boost" , 0.00 , 0.0 .. 0.5 , 0.005 , description = " Speed to add when flying" )
7494 private val rocketSpeed by setting(" Rocket Speed" , 0.0 , 0.0 .. 2.0 , description = " Speed multiplier that the rocket gives you" ) { mode == FlyMode .Enhanced }
7595
7696 private val mute by setting(" Mute Elytra" , false , " Mutes the elytra sound when gliding" )
7797
98+ private var startPos = Vec3d .ZERO
7899 private var jumpThisTick = false
79100 private var previouslyFlying: Boolean? = null
101+ private var passingToPos: Vec3d ? = null
80102 private var glidePause = 0
103+
81104 private var flipFlop = false
82105 private var lastDuration = 1.0
83106 private val fireworkTimer = Timer ()
84107
85108 init {
86109 setDefaultAutomationConfig {
87110 applyEdits {
88- hideAllGroupsExcept(inventoryConfig)
111+ hideAllGroupsExcept(inventoryConfig, rotationConfig )
89112 }
90113 }
91114
@@ -97,14 +120,21 @@ object ElytraFly : Module(
97120 }
98121 }
99122
100- listen< TickEvent . Post > {
101- if (glidePause > 0 ) glidePause --
123+ onEnable {
124+ startPos = player.pos
102125 }
103126
104- listen<PacketEvent .Receive .Post > { event ->
127+ onDisable {
128+ passingToPos = null
129+ if (passObstacles) BaritoneManager .cancel()
130+ }
131+
132+ listen<PacketEvent .Receive .Pre > { event ->
105133 if (event.packet !is PlayerPositionLookS2CPacket ) return @listen
106134 if (mode == FlyMode .Bounce && player.isGliding) {
107- glidePause = flagPause
135+ val snappedDir = getSnappedDir()
136+ val closestLinePoint = player.pos.findClosestPointOnLine(snappedDir)
137+ pathToValidPoint(closestLinePoint, snappedDir, true )
108138 }
109139 }
110140
@@ -161,11 +191,37 @@ object ElytraFly : Module(
161191 }
162192
163193 private fun SafeContext.findFirework (): ItemStack ? {
164- val stack = selectStack(count = 1 ) { isItem( Items .FIREWORK_ROCKET ) }
165- return stack.bestItemMatch(player.hotbarStacks) ? : if (inventory) stack.bestItemMatch(player.hotbarAndInventoryStacks ) else null
194+ val stack = Items .FIREWORK_ROCKET .select()
195+ return stack.bestItemMatch(player.hotbarStacks) ? : if (inventory) stack.bestItemMatch(player.inventoryStacks ) else null
166196 }
167197
168198 private fun SafeContext.onTickBounce () {
199+ if (! BaritoneManager .isActive) passingToPos = null
200+
201+ val playerPos = player.pos
202+ if (passObstacles && playerPos.let { Vec3d (it.x, startPos.y, it.z) } dist startPos > 0.1 ) run obstacleChecks@{
203+ val snappedDir = getSnappedDir()
204+ val closestLinePoint = playerPos.findClosestPointOnLine(snappedDir)
205+ passingToPos?.let { passingTo ->
206+ if (passingTo.isObstructed(snappedDir)) {
207+ pathToValidPoint(passingTo, snappedDir)
208+ }
209+ return
210+ }
211+ if (playerPos dist closestLinePoint <= acceptableOffsetRange) {
212+ if (playerPos.let { Vec3d (it.x, closestLinePoint.y, it.z) }.isObstructed(snappedDir))
213+ pathToValidPoint(closestLinePoint, snappedDir)
214+ else return @obstacleChecks
215+ } else pathToValidPoint(closestLinePoint, snappedDir, true )
216+
217+ return
218+ }
219+
220+ if (glidePause > 0 ) {
221+ glidePause--
222+ return
223+ }
224+
169225 if (autoPitch) rotationRequest { pitch(pitch.toFloat()) }.submit()
170226
171227 if (! player.isGliding) {
@@ -184,6 +240,76 @@ object ElytraFly : Module(
184240 }
185241 }
186242
243+ private fun SafeContext.getSnappedDir (): Vec3d {
244+ val travelDiff = player.pos.subtract(startPos).normalize().let { Vec3d (it.x, 0.0 , it.z) }
245+ return lockYawToStep(travelDiff)
246+ }
247+
248+ context(safeContext: SafeContext )
249+ private fun pathToValidPoint (startSearchPos : Vec3d , dir : Vec3d , initialBlockedCheck : Boolean = false) {
250+ var skippingFirstCheck = ! initialBlockedCheck
251+ var searchPos = startSearchPos
252+ while (skippingFirstCheck || searchPos.isObstructed(dir)) {
253+ searchPos = searchPos.add(dir.multiply(obstacleLookAhead.toDouble()))
254+ skippingFirstCheck = false
255+ }
256+ passTo(searchPos)
257+ safeContext.player.stopGliding()
258+ glidePause = flagPause
259+ }
260+
261+ private fun passTo (pos : Vec3d ) {
262+ passingToPos = pos
263+ BaritoneManager .setGoalAndPath(GoalGetToBlock (pos.flooredBlockPos))
264+ }
265+
266+ context(safeContext: SafeContext )
267+ private fun Vec3d.isObstructed (direction : Vec3d ) =
268+ if (! isLoaded) false
269+ else {
270+ flooredBlockPos.down().let { downPos ->
271+ ! safeContext.blockState(downPos).isSolidBlock(safeContext.world, downPos)
272+ } ||
273+ rayCastObstructed(direction) ||
274+ add(0.0 , 1.0 , 0.0 ).rayCastObstructed(direction) ||
275+ add(0.0 , 2.0 , 0.0 ).rayCastObstructed(direction)
276+ }
277+
278+ context(safeContext: SafeContext )
279+ private fun Vec3d.rayCastObstructed (direction : Vec3d ) =
280+ safeContext.rayCast(
281+ this ,
282+ direction,
283+ obstacleLookAhead.toDouble(),
284+ InteractionMask .Block
285+ )?.blockResult != null
286+
287+ private fun Vec3d.findClosestPointOnLine (snappedDirection : Vec3d ): Vec3d {
288+ val startToCurrent = subtract(startPos)
289+ val t = startToCurrent.dotProduct(snappedDirection) / snappedDirection.dotProduct(snappedDirection)
290+ return startPos.add(snappedDirection.multiply(t))
291+ }
292+
293+ fun lockYawToStep (vector : Vec3d ): Vec3d {
294+ val yaw = atan2(vector.z, vector.x)
295+ val yawDegrees = toDegrees(yaw)
296+
297+ val normalizedYaw = (yawDegrees % 360.0 + 360.0 ) % 360.0
298+
299+ val steps = normalizedYaw / directionStep
300+ val roundedSteps = steps.roundToInt()
301+ val lockedYawDegrees = roundedSteps * directionStep
302+
303+ val normalizedLockedYawDegrees = (lockedYawDegrees % 360.0 + 360.0 ) % 360.0
304+ val lockedYaw = toRadians(normalizedLockedYawDegrees)
305+
306+ val horizontalLength = hypot(vector.x, vector.z)
307+ val x = cos(lockedYaw) * horizontalLength
308+ val z = sin(lockedYaw) * horizontalLength
309+
310+ return Vec3d (x, vector.y, z)
311+ }
312+
187313 @JvmStatic
188314 fun getModifiedBounceVelocity (original : Vec3d ) =
189315 runSafe {
@@ -204,7 +330,12 @@ object ElytraFly : Module(
204330 previouslyFlying = original
205331 return @runSafe original
206332 }
207- return if (isEnabled && mode == FlyMode .Bounce && previouslyFlying == true && glidePause <= 0 ) true
333+ return if (
334+ isEnabled &&
335+ mode == FlyMode .Bounce &&
336+ previouslyFlying == true &&
337+ glidePause <= 0 &&
338+ ! BaritoneManager .isActive) true
208339 else {
209340 previouslyFlying = original
210341 original
0 commit comments