Skip to content

Commit 605c098

Browse files
committed
1x2 tunnel bounce efly and fake fly
1 parent cf89417 commit 605c098

9 files changed

Lines changed: 127 additions & 85 deletions

File tree

src/main/java/com/lambda/mixin/entity/ClientPlayerEntityMixin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void wrapTick(Input input, Operation<Void> original) {
105105

106106
@Inject(method = "tickMovement", at = @At("RETURN"))
107107
private void injectTickMovement(CallbackInfo ci) {
108-
if (NoJumpCooldown.INSTANCE.isEnabled() || (ElytraFly.INSTANCE.isEnabled() && ElytraFly.getMode() == ElytraFly.FlyMode.Bounce)) jumpingCooldown = 0;
108+
if (NoJumpCooldown.INSTANCE.isEnabled() || ElytraFly.getBounceMode().isEnabled()) jumpingCooldown = 0;
109109
}
110110

111111
@ModifyExpressionValue(method = "sendMovementPackets", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;getYaw()F"))

src/main/java/com/lambda/mixin/entity/EntityMixin.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.lambda.interaction.BaritoneHandler;
2424
import com.lambda.interaction.managers.rotating.RotationManager;
2525
import com.lambda.module.modules.movement.elytrafly.ElytraFly;
26-
import com.lambda.module.modules.movement.elytrafly.ElytraFly.FlyMode;
2726
import com.lambda.module.modules.render.NoRender;
2827
import com.lambda.util.math.Vec2d;
2928
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
@@ -181,7 +180,7 @@ private boolean injectIsSprinting(boolean original) {
181180
var player = getMc().player;
182181
if ((Object) this != getMc().player) return original;
183182

184-
if (ElytraFly.INSTANCE.isEnabled() && ElytraFly.getMode() == FlyMode.Bounce && player.isGliding())
183+
if (ElytraFly.getBounceMode().isEnabled() && player.isGliding())
185184
return true;
186185

187186
return original;
@@ -192,7 +191,7 @@ private EntityPose injectGetPose(EntityPose original) {
192191
var player = getMc().player;
193192
if ((Object) this != getMc().player) return original;
194193

195-
if (ElytraFly.INSTANCE.isDisabled() || ElytraFly.getMode() != FlyMode.Bounce || !player.isGliding()) return original;
194+
if (!ElytraFly.getBounceMode().isEnabled() || !player.isGliding()) return original;
196195

197196
return EntityPose.GLIDING;
198197
}
@@ -204,7 +203,7 @@ private float modifyGetYaw(float original) {
204203

205204
@Inject(method = "getVelocity", at = @At("HEAD"), cancellable = true)
206205
private void injectGetVelocity(CallbackInfoReturnable<Vec3d> cir) {
207-
if (ElytraFly.INSTANCE.isDisabled() || ElytraFly.getMode() != FlyMode.Bounce) return;
206+
if (!ElytraFly.getBounceMode().isEnabled()) return;
208207
cir.setReturnValue(ElytraFly.getBounceMode().getModifiedVelocity(velocity));
209208
}
210209
}

src/main/java/com/lambda/mixin/entity/FireworkRocketEntityMixin.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
public class FireworkRocketEntityMixin {
3131
@WrapOperation(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setVelocity(Lnet/minecraft/util/math/Vec3d;)V"))
3232
private void wrapSetVelocity(LivingEntity shooter, Vec3d vec3d, Operation<Void> original) {
33-
if (ElytraFly.INSTANCE.isEnabled()) {
34-
ElytraFly.boostRocket();
35-
} else original.call(shooter, vec3d);
33+
if (ElytraFly.INSTANCE.isEnabled()) ElytraFly.boostRocket();
34+
else original.call(shooter, vec3d);
3635
}
3736
}

src/main/java/com/lambda/mixin/entity/LivingEntityMixin.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private void wrapPushAwayFrom(Entity entity, Operation<Void> original) {
186186
private boolean injectIsGliding(boolean original) {
187187
if (lambda$instance != Lambda.getMc().player) return original;
188188

189-
return (ElytraFly.INSTANCE.isEnabled() && ElytraFly.getMode() == ElytraFly.FlyMode.Bounce)
189+
return ElytraFly.getBounceMode().isEnabled()
190190
? ElytraFly.getBounceMode().isGliding()
191191
: original;
192192
}
@@ -195,8 +195,7 @@ private boolean injectIsGliding(boolean original) {
195195
private void injectTravelGliding(Vec3d movementInput, CallbackInfo ci) {
196196
if (lambda$instance != Lambda.getMc().player) return;
197197
final var grimMode = ElytraFly.getGrimControlMode();
198-
if (ElytraFly.INSTANCE.isEnabled() &&
199-
ElytraFly.getMode() == ElytraFly.FlyMode.GrimControl &&
198+
if (ElytraFly.getGrimControlMode().isEnabled() &&
200199
!grimMode.getFlipFlopMode().isFlipFlopping().invoke(grimMode.getHasFirework()) &&
201200
!grimMode.getMoving()
202201
) ci.cancel();

src/main/kotlin/com/lambda/module/modules/movement/elytrafly/ElytraFly.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ object ElytraFly : Module(
5151

5252
private val boostSpeed by setting("Boost", 0.00, 0.0..0.5, 0.005, description = "Speed to add when flying")
5353
private val rocketSpeed by setting("Rocket Speed", 1.0, 0.0..2.0, 0.01, description = "Speed multiplier that the rocket gives you")
54+
val fakeFly by setting("Fake Fly", false, "Rapidly swaps the chestplate and elytra to give the appearance the player is flying without an elytra. May also reduce durability loss")
5455
private val mute by setting("Mute Elytra", false, "Mutes the elytra sound when gliding")
5556

5657
private const val BOUNCE_TAB = "Bounce"

src/main/kotlin/com/lambda/module/modules/movement/elytrafly/ElytraFlyMode.kt

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,27 @@ import com.lambda.config.ConfigBlock
2121
import com.lambda.context.Automated
2222
import com.lambda.context.SafeContext
2323
import com.lambda.event.Muteable
24+
import com.lambda.interaction.managers.inventory.InventoryRequest
25+
import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest
26+
import com.lambda.interaction.material.StackSelection.Companion.selectStack
2427
import com.lambda.module.modules.movement.elytrafly.ElytraFly.FlyMode
28+
import com.lambda.module.modules.movement.elytrafly.ElytraFly.fakeFly
2529
import com.lambda.threading.runSafe
30+
import com.lambda.util.CommunicationUtils.logError
31+
import com.lambda.util.player.SlotUtils.armorSlots
32+
import com.lambda.util.player.SlotUtils.hotbarSlots
33+
import com.lambda.util.player.SlotUtils.inventorySlots
2634
import net.minecraft.entity.Entity
35+
import net.minecraft.entity.EquipmentSlot
36+
import net.minecraft.item.Items
2737
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
38+
import net.minecraft.screen.slot.Slot
2839

2940
abstract class ElytraFlyMode(
3041
val flyMode: FlyMode
3142
) : Muteable, Automated by ElytraFly, ConfigBlock {
32-
override val isMuted get() = ElytraFly.isMuted || ElytraFly.mode != flyMode
43+
override val isMuted get() = !isEnabled
44+
val isEnabled get() = ElytraFly.isEnabled && ElytraFly.mode == flyMode
3345

3446
val onEnableListeners = mutableListOf<SafeContext.() -> Unit>()
3547
val onDisableListeners = mutableListOf<SafeContext.() -> Unit>()
@@ -42,6 +54,61 @@ abstract class ElytraFlyMode(
4254

4355
open fun isGliding(): Boolean? = runSafe { player.getFlag(Entity.GLIDING_FLAG_INDEX) }
4456

57+
fun SafeContext.flyOrFakeFly() {
58+
if (!fakeFly) {
59+
startFly()
60+
return
61+
}
62+
63+
player.inventory.equipment.get(EquipmentSlot.CHEST).let { chestStack ->
64+
if (chestStack.item == Items.ELYTRA) {
65+
logError("Fake Fly requires that you don't have an elytra equipped")
66+
ElytraFly.disable()
67+
return
68+
}
69+
}
70+
71+
val elytraSlot = findElytra() ?: run {
72+
logError("Fake Fly requires an elytra in your inventory, preferably in your hotbar.")
73+
ElytraFly.disable()
74+
return
75+
}
76+
val elytraInHotbar = elytraSlot.index in 0..8
77+
78+
val chestSlot = player.armorSlots[1]
79+
val chestSlotEmpty = chestSlot.stack.isEmpty
80+
81+
fun InventoryRequest.InvRequestBuilder.swapChest() {
82+
if (elytraInHotbar) swap(chestSlot.id, elytraSlot.index)
83+
else {
84+
moveSlot(elytraSlot.id, chestSlot.id)
85+
if (!chestSlotEmpty) pickup(elytraSlot.id)
86+
}
87+
}
88+
89+
inventoryRequest {
90+
swapChest()
91+
action { startFly() }
92+
swapChest()
93+
}.submit(false)
94+
}
95+
96+
fun SafeContext.findElytra(): Slot? =
97+
selectStack {
98+
isItem(Items.ELYTRA)
99+
.and { it.damage < it.maxDamage }
100+
}.run {
101+
filterSlots(player.hotbarSlots)
102+
.firstOrNull()
103+
?: filterSlots(player.inventorySlots)
104+
.firstOrNull()
105+
}
106+
107+
fun SafeContext.startFly() {
108+
player.setFlag(Entity.GLIDING_FLAG_INDEX, true)
109+
startFlyPacket()
110+
}
111+
45112
protected fun SafeContext.startFlyPacket() =
46113
connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING))
47114
}

src/main/kotlin/com/lambda/module/modules/movement/elytrafly/ObstaclePassingMode.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ abstract class ObstaclePassingMode(
180180
flooredBlockPos.down().let { downPos ->
181181
!safeContext.blockState(downPos).isSolidBlock(safeContext.world, downPos)
182182
} ||
183-
add(0.0, passerConfig.minObstacleHeight, 0.0).rayCastObstructed(direction) ||
184-
add(0.0, 1.01, 0.0).rayCastObstructed(direction) ||
185-
add(0.0, 1.99, 0.0).rayCastObstructed(direction)
183+
if (add(0.0, passerConfig.minObstacleHeight, 0.0).rayCastObstructed(direction)) true
184+
else if (passerConfig.headHitters) {
185+
(add(0.0, 1.01, 0.0).rayCastObstructed(direction) ||
186+
add(0.0, 1.99, 0.0).rayCastObstructed(direction))
187+
} else false
186188
}
187189

188190
context(safeContext: SafeContext)
@@ -200,7 +202,8 @@ class PasserSettings(override val c: Config) : ConfigBlock {
200202
val passObstacles by c.setting("Pass Obstacles", true, "Automatically paths around obstacles using baritone")
201203
val walkWhenFlagged by c.setting("Walk When Flagged", true, "Triggers obstacle passer when the server forces your position (typically getting flagged by the anticheat)") { passObstacles }
202204
val minObstacleHeight by c.setting("Min Obstacle Height", 0.063, 0.0..1.0, 0.0001, "The minimum height an obstacle must be above the ground to trigger obstacle passer") { passObstacles }
205+
val headHitters by c.setting("Head Hitters", true, "Flags obstacles above the y level you started flying at") { passObstacles }
203206
val acceptableOffsetRange by c.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") { passObstacles }
204-
val obstacleLookAhead by c.setting("Obstacle Look-Ahead", 15, 0..50, 1, "Looks ahead of the player to see if obstacles are in the way") { passObstacles }
207+
val obstacleLookAhead by c.setting("Obstacle Look-Ahead", 8, 0..50, 1, "Looks ahead of the player to see if obstacles are in the way") { passObstacles }
205208
val directionStep by c.setting("Direction Step", 45.0, 0.0..180.0, 0.1, "The step size to use when locking the flight direction") { passObstacles }
206209
}

src/main/kotlin/com/lambda/module/modules/movement/elytrafly/modes/BounceElytraFly.kt

Lines changed: 39 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,31 @@ import com.lambda.config.Config
2121
import com.lambda.config.Group
2222
import com.lambda.context.SafeContext
2323
import com.lambda.event.events.MovementEvent
24+
import com.lambda.event.events.PacketEvent
2425
import com.lambda.event.events.TickEvent
2526
import com.lambda.event.listener.SafeListener.Companion.listen
2627
import com.lambda.interaction.BaritoneHandler
27-
import com.lambda.interaction.managers.inventory.InventoryRequest
28-
import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest
2928
import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest
3029
import com.lambda.interaction.managers.rotating.RotationManager
31-
import com.lambda.interaction.material.StackSelection.Companion.selectStack
3230
import com.lambda.module.hud.Speedometer
3331
import com.lambda.module.modules.movement.BetterFirework.isElytraEquipped
34-
import com.lambda.module.modules.movement.elytrafly.ElytraFly
3532
import com.lambda.module.modules.movement.elytrafly.ElytraFly.FlyMode
33+
import com.lambda.module.modules.movement.elytrafly.ElytraFly.fakeFly
3634
import com.lambda.module.modules.movement.elytrafly.ObstaclePassingMode
3735
import com.lambda.module.modules.movement.elytrafly.PasserSettings
3836
import com.lambda.threading.runSafe
39-
import com.lambda.util.CommunicationUtils.logError
37+
import com.lambda.util.PacketUtils.handlePacketSilently
38+
import com.lambda.util.PacketUtils.sendPacketSilently
4039
import com.lambda.util.SpeedUnit
4140
import com.lambda.util.TickTimer
42-
import com.lambda.util.player.SlotUtils.armorSlots
43-
import com.lambda.util.player.SlotUtils.hotbarSlots
44-
import com.lambda.util.player.SlotUtils.inventorySlots
4541
import net.minecraft.client.network.ClientPlayerEntity
4642
import net.minecraft.entity.Entity
47-
import net.minecraft.entity.EquipmentSlot
4843
import net.minecraft.entity.effect.StatusEffects
49-
import net.minecraft.item.Items
50-
import net.minecraft.screen.slot.Slot
44+
import net.minecraft.network.packet.Packet
45+
import net.minecraft.network.packet.s2c.common.CommonPingS2CPacket
5146
import net.minecraft.util.math.Vec3d
47+
import java.util.*
48+
import java.util.concurrent.ConcurrentLinkedQueue
5249
import kotlin.math.abs
5350

5451
class BounceElytraFly(
@@ -63,9 +60,9 @@ class BounceElytraFly(
6360
private val autoPitch by c.setting("Auto Pitch", true, "Automatically pitches the players rotation down to bounce at faster speeds")
6461
private val pitch by c.setting("Pitch", 80.0, -90.0..90.0, 0.000001) { autoPitch }
6562
private val jump by c.setting("Jump", true, "Automatically jumps")
66-
private val fakeFly by c.setting("Fake Fly", false, "Rapidly swaps the chestplate and elytra to give the appearance the player is flying without an elytra. May also reduce durability loss")
6763
private val flagPause by c.setting("FlagPause Pause", 5, 0..100, 1, "How long to pause if the server flags you for a movement check", "ticks")
6864
private val minimizePackets by c.setting("Minimize Packets", true, "Shrinks the amount of start fly packets sent to the server as much as possible")
65+
private val fakeLag by c.setting("Fake Lag", true, "Emulates the player lagging to allow flying in 1x2 tunnels")
6966

7067
@Group(Y_MOTION_GROUP) val yMotionSetting by c.setting("Y Motion", false, "Cancels the players y velocity to aid speed")
7168
@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 }
@@ -87,6 +84,8 @@ class BounceElytraFly(
8784
private var jumpThisTick = false
8885
private var prevGliding: Boolean? = null
8986
private val pauseTimer = TickTimer()
87+
private val pingPackets = ConcurrentLinkedQueue<CommonPingS2CPacket>()
88+
private val sendPacketQueue = LinkedList<Packet<*>>()
9089

9190
private val ClientPlayerEntity.canTakeoff: Boolean
9291
get() = (isOnGround || canOpenElytra) && (isElytraEquipped xor fakeFly)
@@ -100,6 +99,10 @@ class BounceElytraFly(
10099
!this.hasVehicle() &&
101100
!this.hasStatusEffect(StatusEffects.LEVITATION)
102101

102+
private val SafeContext.queuePackets
103+
get() = fakeLag && player.isGliding &&
104+
player.y - startPos.y < if (passerConfig.passObstacles) passerConfig.minObstacleHeight + 0.1 else 0.163
105+
103106
init {
104107
listen<TickEvent.Pre> {
105108
pauseTimer.tick()
@@ -112,52 +115,15 @@ class BounceElytraFly(
112115

113116
if (!player.isGliding) {
114117
if (takeoff && player.canTakeoff) {
115-
if (player.canOpenElytra) {
116-
player.startGliding()
117-
startFlyPacket()
118-
} else jumpThisTick = true
118+
if (player.canOpenElytra) flyOrFakeFly()
119+
else jumpThisTick = true
119120
}
120121
return@listen
121122
}
122123

123124
if (minimizePackets && player.getFlag(Entity.GLIDING_FLAG_INDEX) && !fakeFly && !yMotion) return@listen
124125

125-
if (!fakeFly) {
126-
fly()
127-
return@listen
128-
}
129-
130-
player.inventory.equipment.get(EquipmentSlot.CHEST).let { chestStack ->
131-
if (chestStack.item == Items.ELYTRA) {
132-
logError("Fake Fly requires that you don't have an elytra equipped")
133-
ElytraFly.disable()
134-
return@listen
135-
}
136-
}
137-
138-
val elytraSlot = findElytra() ?: run {
139-
logError("Fake Fly requires an elytra in your inventory, preferably in your hotbar.")
140-
ElytraFly.disable()
141-
return@listen
142-
}
143-
val elytraInHotbar = elytraSlot.index in 0..8
144-
145-
val chestSlot = player.armorSlots[1]
146-
val chestSlotEmpty = chestSlot.stack.isEmpty
147-
148-
fun InventoryRequest.InvRequestBuilder.swapChest() {
149-
if (elytraInHotbar) swap(chestSlot.id, elytraSlot.index)
150-
else {
151-
moveSlot(elytraSlot.id, chestSlot.id)
152-
if (!chestSlotEmpty) pickup(elytraSlot.id)
153-
}
154-
}
155-
156-
inventoryRequest {
157-
swapChest()
158-
action { fly() }
159-
swapChest()
160-
}.submit(false)
126+
flyOrFakeFly()
161127
}
162128

163129
listen<MovementEvent.InputUpdate> { event ->
@@ -167,23 +133,30 @@ class BounceElytraFly(
167133
}
168134
}
169135

170-
onFlag { pauseTimer.reset() }
171-
}
136+
listen<PacketEvent.Send.Pre>({ 1 }) { event ->
137+
if (queuePackets) {
138+
sendPacketQueue.add(event.packet)
139+
event.cancel()
140+
return@listen
141+
}
172142

173-
fun SafeContext.findElytra(): Slot? =
174-
selectStack {
175-
isItem(Items.ELYTRA)
176-
.and { it.damage < it.maxDamage }
177-
}.run {
178-
filterSlots(player.hotbarSlots)
179-
.firstOrNull()
180-
?: filterSlots(player.inventorySlots)
181-
.firstOrNull()
143+
while (sendPacketQueue.isNotEmpty()) {
144+
val packet = sendPacketQueue.poll()
145+
connection.sendPacketSilently(packet)
146+
}
147+
while (pingPackets.isNotEmpty()) {
148+
val packet = pingPackets.poll()
149+
connection.handlePacketSilently(packet)
150+
}
151+
}
152+
listen<PacketEvent.Receive.Pre>({ 1 }) { event ->
153+
if (event.packet is CommonPingS2CPacket && queuePackets) {
154+
pingPackets.add(event.packet)
155+
event.cancel()
156+
}
182157
}
183158

184-
fun SafeContext.fly() {
185-
player.setFlag(Entity.GLIDING_FLAG_INDEX, true)
186-
startFlyPacket()
159+
onFlag { pauseTimer.reset() }
187160
}
188161

189162
fun getModifiedVelocity(original: Vec3d) =

0 commit comments

Comments
 (0)