@@ -39,15 +39,23 @@ import com.lambda.util.PacketUtils.handlePacketSilently
3939import com.lambda.util.PacketUtils.sendPacketSilently
4040import com.lambda.util.SpeedUnit
4141import com.lambda.util.TickTimer
42+ import com.lambda.util.math.distSq
43+ import com.lambda.util.math.minus
4244import com.lambda.util.player.PlayerUtils.canStartGliding
4345import com.lambda.util.player.PlayerUtils.canTakeoff
46+ import net.minecraft.client.input.KeyboardInput.getMovementMultiplier
4447import net.minecraft.entity.Entity
4548import net.minecraft.network.packet.Packet
4649import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket
50+ import net.minecraft.util.PlayerInput
51+ import net.minecraft.util.math.Vec2f
4752import net.minecraft.util.math.Vec3d
4853import java.util.*
4954import java.util.concurrent.ConcurrentLinkedQueue
5055import kotlin.math.abs
56+ import kotlin.math.cos
57+ import kotlin.math.pow
58+ import kotlin.math.sin
5159
5260class BounceElytraFly (
5361 override val c : Config
@@ -69,33 +77,43 @@ class BounceElytraFly(
6977 @Group(Y_MOTION_GROUP ) val yMotionSetting by c.setting(" Y Motion" , false , " Cancels the players y velocity to aid speed" )
7078 @Group(Y_MOTION_GROUP ) val onlyOnDiagonal: Boolean by c.setting(" Only On Diagonal" , true , " Only use y motion when the player is flying on a non-axial angle" ) { yMotionSetting }
7179 @Group(Y_MOTION_GROUP ) val minDiagonalAngle by c.setting(" Min Diagonal Angle" , 15.0 , 0.0 .. 180.0 , 0.1 , " The minimum angle the player must be flying to use y motion" ) { yMotionSetting && onlyOnDiagonal }
80+ @Group(Y_MOTION_GROUP ) val strictYMotionRange by c.setting(" Strict Range" , true , " provides an extra range check to sneak until within. Typically used for when you need to get within sub-block distances of walls for collision checks" ) { yMotionSetting }
81+ @Group(Y_MOTION_GROUP ) val acceptableYMotionRange by c.setting(" Acceptable Range" , 0.1 , 0.01 .. 5.0 , 0.01 , " The acceptable distance, aside from forward distance, from the start position" ) { yMotionSetting && strictYMotionRange }
7282 @Group(Y_MOTION_GROUP ) val yMotionStartSpeed by c.setting(" Y Motion Start Speed" , 30 , 0 .. 40 , 1 , unit = " bps" ) { yMotionSetting }
7383 @Group(Y_MOTION_GROUP ) val speedLimit by c.setting(" Speed Limit" , 110 , 10 .. 400 , 1 , unit = " bps" ) { yMotionSetting }
74- context(safeContext: SafeContext )
75- private val yMotion
84+ private val SafeContext .yMotion
7685 get() = yMotionSetting &&
77- (! onlyOnDiagonal || run {
78- val normalised = abs(RotationManager .activeRotation.yaw % 90 )
79- normalised > minDiagonalAngle && normalised < 90 - minDiagonalAngle
80- }) &&
81- safeContext.player.isOnGround &&
82- safeContext.player.isGliding &&
86+ onYMotionAngle &&
87+ player.isOnGround &&
88+ player.isGliding &&
8389 Speedometer .calculateSpeed(true , SpeedUnit .BlocksPerSecond ).let { speed ->
8490 speed > yMotionStartSpeed && speed < speedLimit
8591 }
8692
93+ private val onYMotionAngle
94+ get() = ! onlyOnDiagonal || diagonal
95+
8796 @Group(BOUNCE_OBSTACLE_PASSER_GROUP ) override val passerConfig by c.configBlock(PasserSettings (c))
8897
8998 private var jumpThisTick = false
9099 private var prevGliding: Boolean? = null
91100 private val pauseTimer = TickTimer ()
92101 private val pingPackets = ConcurrentLinkedQueue <CommonPingS2CPacket >()
93102 private val sendPacketQueue = LinkedList <Packet <* >>()
103+ private var sneakLeft = false
104+ private var sneakRight = false
105+ private var interrupting = false
94106
95107 private val SafeContext .queuePackets
96- get() = fakeLag && player.isGliding && ! yMotion &&
108+ get() = fakeLag && player.isGliding && ( ! yMotionSetting || ! onYMotionAngle) &&
97109 player.y - startPos.y < if (passerConfig.passObstacles) passerConfig.minObstacleHeight + 0.1 else 0.163
98110
111+ private val diagonal: Boolean
112+ get() {
113+ val normalised = abs(RotationManager .activeRotation.yaw % 90 )
114+ return normalised > minDiagonalAngle && normalised < 90 - minDiagonalAngle
115+ }
116+
99117 init {
100118 listen<TickEvent .Pre > {
101119 pauseTimer.tick()
@@ -104,12 +122,44 @@ class BounceElytraFly(
104122
105123 if (handlePassingObstacles()) return @listen
106124
125+ if (yMotionSetting && strictYMotionRange && onYMotionAngle && player.isOnGround) {
126+ val snappedDir = getSnappedDir()
127+ val closestLinePoint = player.pos.findClosestPointOnLine(snappedDir)
128+ val xz = Vec3d (player.x, closestLinePoint.y, player.z)
129+ if (xz distSq closestLinePoint > acceptableYMotionRange.pow(2 )) {
130+ if (player.isGliding) {
131+ interrupt()
132+ return @listen
133+ }
134+ val offset = player.pos - startPos
135+ val cross = snappedDir.x * offset.z - snappedDir.z * offset.x
136+ val rotationRequest = rotationRequest {
137+ val yawAndPitch = snappedDir.yawAndPitch
138+ yaw(yawAndPitch.y)
139+ }.submit()
140+ if (! rotationRequest.done) return @listen
141+ sneakLeft = cross > 0
142+ sneakRight = ! sneakLeft
143+ return @listen
144+ }
145+ }
146+
107147 if (! pauseTimer.hasSurpassed(flagPause)) return @listen
108148
109149 if (! player.isGliding) {
110150 if (takeoff && player.canTakeoff) {
111151 if (player.canStartGliding) GlideHandler .onGlide()
112- else jumpThisTick = true
152+ else {
153+ val yawRad = Math .toRadians(player.yaw.toDouble())
154+ val rightX = - cos(yawRad)
155+ val rightZ = - sin(yawRad)
156+ val vx = player.velocity.x
157+ val vz = player.velocity.z
158+ val sidewaysSpeed = abs(vx * rightX + vz * rightZ)
159+ if (sidewaysSpeed >= 0.001 ) return @listen
160+
161+ jumpThisTick = true
162+ }
113163 }
114164 return @listen
115165 }
@@ -119,9 +169,33 @@ class BounceElytraFly(
119169 flyOrFakeFly()
120170 }
121171
172+ listen<TickEvent .Post >({ - 100 }) {
173+ interrupting = false
174+ }
175+
122176 listen<MovementEvent .InputUpdate > { event ->
123- if ((player.isGliding && jump) || jumpThisTick) {
124- event.input.jump()
177+ val input = event.input
178+ val playerInput = input.playerInput
179+ if (sneakLeft || sneakRight) {
180+ input.playerInput = PlayerInput (
181+ playerInput.forward,
182+ playerInput.backward,
183+ sneakLeft,
184+ sneakRight,
185+ playerInput.jump,
186+ true ,
187+ false
188+ )
189+ input.movementVector = Vec2f (
190+ getMovementMultiplier(sneakLeft, sneakRight),
191+ 0f
192+ )
193+ sneakLeft = false
194+ sneakRight = false
195+ return @listen
196+ }
197+ if ((player.isGliding && ! interrupting && jump) || jumpThisTick) {
198+ input.jump()
125199 jumpThisTick = false
126200 }
127201 }
@@ -145,11 +219,18 @@ class BounceElytraFly(
145219 onFlag { pauseTimer.reset() }
146220
147221 onDisable {
222+ jumpThisTick = false
148223 prevGliding = false
149224 flushPackets()
225+ sneakLeft = false
226+ sneakRight = false
150227 }
151228 }
152229
230+ override fun interrupt () {
231+ interrupting = true
232+ }
233+
153234 private fun SafeContext.flushPackets () {
154235 while (sendPacketQueue.isNotEmpty()) {
155236 val packet = sendPacketQueue.poll()
@@ -171,6 +252,7 @@ class BounceElytraFly(
171252 runSafe {
172253 val original: Boolean = player.getFlag(Entity .GLIDING_FLAG_INDEX )
173254 if (prevGliding == true &&
255+ ! interrupting &&
174256 pauseTimer.hasSurpassed(flagPause) &&
175257 ! BaritoneHandler .isActive) true
176258 else {
0 commit comments