Skip to content

Commit 3f21fd5

Browse files
committed
almost flawless firework grim control efly with no rotation spam to stay in place, and incredibly minimal rubberbanding when moving from stationary in mid-air. Seems to be completely reliable from testing
1 parent 3fd52bf commit 3f21fd5

7 files changed

Lines changed: 130 additions & 60 deletions

File tree

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
import com.lambda.event.EventFlow;
2222
import com.lambda.event.events.MovementEvent;
2323
import com.lambda.interaction.managers.rotating.RotationManager;
24-
import com.lambda.module.modules.movement.elytrafly.ElytraFly;
2524
import com.lambda.module.modules.movement.Velocity;
25+
import com.lambda.module.modules.movement.elytrafly.ElytraFly;
2626
import com.lambda.module.modules.render.ViewModel;
2727
import com.llamalad7.mixinextras.expression.Definition;
2828
import com.llamalad7.mixinextras.expression.Expression;
@@ -181,4 +181,14 @@ private boolean injectIsGliding(boolean original) {
181181
? ElytraFly.getBounceMode().isGliding()
182182
: original;
183183
}
184+
185+
@Inject(method = "travelGliding", at = @At("HEAD"), cancellable = true)
186+
private void injectTravelGliding(Vec3d movementInput, CallbackInfo ci) {
187+
if (lambda$instance != Lambda.getMc().player) return;
188+
if (ElytraFly.INSTANCE.isEnabled() &&
189+
ElytraFly.getMode() == ElytraFly.FlyMode.GrimControl &&
190+
ElytraFly.getGrimControlMode().getNoFlipFlop() &&
191+
!ElytraFly.getGrimControlMode().getMoving()
192+
) ci.cancel();
193+
}
184194
}

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

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717

1818
package com.lambda.module.modules.movement.elytrafly
1919

20-
import com.lambda.config.ConfigEditor
21-
import com.lambda.config.ConfigEditor.forEachSetting
20+
import com.lambda.config.ConfigEditor.hideAllExcept
2221
import com.lambda.config.Tab
2322
import com.lambda.config.automation.AutomationConfig.Companion.setDefaultAutomationConfig
2423
import com.lambda.config.entries.Setting.Companion.onValueChange
@@ -44,32 +43,30 @@ object ElytraFly : Module(
4443
description = "Allows you to fly with an elytra",
4544
tag = ModuleTag.MOVEMENT,
4645
) {
47-
private const val MODE_TAB = "Mode"
48-
private const val EXTRA_TAB = "Extra"
49-
50-
@Tab(MODE_TAB) @JvmStatic val mode by setting("Fly Mode", FlyMode.Bounce)
46+
@JvmStatic val mode by setting("Fly Mode", FlyMode.Bounce)
5147
.onValueChange { from, to ->
5248
from.elytraFly?.onDisableListeners?.forEach { it() }
5349
to.elytraFly?.onEnableListeners?.forEach { it() }
5450
}
5551

56-
@Tab(MODE_TAB) @JvmStatic val bounceMode by configBlock(BounceElytraFly(this))
57-
.withEdits { forEachSetting { visibility { old -> { old() && mode == FlyMode.Bounce } } } }
58-
@Tab(MODE_TAB) @JvmStatic val controlMode by configBlock(ControlElytraFly(this))
59-
.withEdits { forEachSetting { visibility { old -> { old() && mode == FlyMode.Control } } } }
60-
@Tab(MODE_TAB) @JvmStatic val grimControlMode by configBlock(GrimControlElytraFly(this))
61-
.withEdits { forEachSetting { visibility { old -> { old() && mode == FlyMode.GrimControl } } } }
62-
@Tab(MODE_TAB) @JvmStatic val packetMode by configBlock(PacketElytraFly(this))
63-
.withEdits { forEachSetting { visibility { old -> { old() && mode == FlyMode.Packet } } } }
52+
private val boostSpeed by setting("Boost", 0.00, 0.0..0.5, 0.005, description = "Speed to add when flying")
53+
private val rocketSpeed by setting("Rocket Speed", 1.0, 0.0..2.0, description = "Speed multiplier that the rocket gives you")
54+
private val mute by setting("Mute Elytra", false, "Mutes the elytra sound when gliding")
55+
56+
private const val BOUNCE_TAB = "Bounce"
57+
private const val CONTROL_TAB = "Control"
58+
private const val GRIM_CONTROL_TAB = "Grim Control"
59+
private const val PACKET_TAB = "Packet"
6460

65-
@Tab(EXTRA_TAB) private val boostSpeed by setting("Boost", 0.00, 0.0..0.5, 0.005, description = "Speed to add when flying")
66-
@Tab(EXTRA_TAB) private val rocketSpeed by setting("Rocket Speed", 1.0, 0.0..2.0, description = "Speed multiplier that the rocket gives you")
67-
@Tab(EXTRA_TAB) private val mute by setting("Mute Elytra", false, "Mutes the elytra sound when gliding")
61+
@Tab(BOUNCE_TAB) @JvmStatic val bounceMode by configBlock(BounceElytraFly(this))
62+
@Tab(GRIM_CONTROL_TAB) @JvmStatic val grimControlMode by configBlock(GrimControlElytraFly(this))
63+
@Tab(CONTROL_TAB) @JvmStatic val controlMode by configBlock(ControlElytraFly(this))
64+
@Tab(PACKET_TAB) @JvmStatic val packetMode by configBlock(PacketElytraFly(this))
6865

6966
init {
7067
setDefaultAutomationConfig()
7168
.withEdits {
72-
ConfigEditor.hideAllExcept(::inventoryConfig, ::rotationConfig)
69+
hideAllExcept(::inventoryConfig, ::rotationConfig)
7370
}
7471

7572
onEnable { mode.elytraFly?.onEnableListeners?.forEach { it() } }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
2929
abstract class ElytraFlyMode(
3030
val flyMode: FlyMode
3131
) : Muteable, Automated by ElytraFly, ConfigBlock {
32-
override val isMuted get() = ElytraFly.isDisabled || ElytraFly.mode != flyMode
32+
override val isMuted get() = ElytraFly.isMuted || ElytraFly.mode != flyMode
3333

3434
val onEnableListeners = mutableListOf<SafeContext.() -> Unit>()
3535
val onDisableListeners = mutableListOf<SafeContext.() -> Unit>()

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.lambda.module.hud.Speedometer
2626
import com.lambda.module.modules.movement.elytrafly.ElytraFly.FlyMode
2727
import com.lambda.threading.runGameScheduled
2828
import com.lambda.util.BlockUtils.blockState
29+
import com.lambda.util.CommunicationUtils.logError
2930
import com.lambda.util.SpeedUnit
3031
import com.lambda.util.math.dist
3132
import com.lambda.util.math.flooredBlockPos
@@ -69,6 +70,12 @@ abstract class ObstaclePassingMode(
6970
}
7071

7172
fun SafeContext.handlePassingObstacles(): Boolean {
73+
if (!BaritoneHandler.baritoneAvailable) {
74+
logError("Obstacle passing requires baritone to be installed!")
75+
ElytraFly.disable()
76+
return true
77+
}
78+
7279
if (!BaritoneHandler.isActive) passingToPos = null
7380

7481
if (!passerConfig.passObstacles) return false

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

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,50 @@ package com.lambda.module.modules.movement.elytrafly.modes
1919

2020
import com.lambda.config.Config
2121
import com.lambda.context.SafeContext
22+
import com.lambda.event.events.PacketEvent
23+
import com.lambda.event.events.PlayerPacketEvent
2224
import com.lambda.event.events.TickEvent
2325
import com.lambda.event.listener.SafeListener.Companion.listen
2426
import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotationRequest
27+
import com.lambda.interaction.managers.rotating.RotationManager
2528
import com.lambda.interaction.material.StackSelection.Companion.select
2629
import com.lambda.module.modules.movement.BetterFirework.startFirework
2730
import com.lambda.module.modules.movement.elytrafly.ElytraFly.FlyMode
2831
import com.lambda.module.modules.movement.elytrafly.ElytraFlyMode
32+
import com.lambda.util.TickTimer
2933
import com.lambda.util.Timer
34+
import com.lambda.util.math.MathUtils.toFloat
3035
import com.lambda.util.player.SlotUtils.hotbarStacks
3136
import com.lambda.util.player.SlotUtils.inventoryStacks
3237
import com.lambda.util.player.hasFirework
3338
import net.minecraft.component.DataComponentTypes
3439
import net.minecraft.item.ItemStack
3540
import net.minecraft.item.Items
41+
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket
3642
import net.minecraft.util.math.Vec3d
3743
import kotlin.time.Duration.Companion.seconds
3844

3945
class GrimControlElytraFly(override val c: Config) : ElytraFlyMode(FlyMode.GrimControl) {
4046
private val inventory by c.setting("Inventory", true, "Allow using fireworks from the players inventory")
47+
private val safetyMargin by c.setting("Safety Margin", 0.2, 0.0..2.0, 0.01, "The time (in seconds) to shorten the firework use delay to account for ping variation", "s")
48+
val noFlipFlop by c.setting("No Flip Flop", true, "Stops flying completely rather than the usual back and forth.")
49+
private val packetGap by c.setting("Packet Gap", 5, 0..100, 1, "The gap between allowing player movement packets to pass") { noFlipFlop }
4150

4251
private var flipFlop = false
43-
private var lastDuration = 1.0
52+
private var rotFlipFlop = false
53+
private var lastDuration = -1.0
4454
private val fireworkTimer = Timer()
55+
var still = false
56+
var moving = false
57+
// Seems to be a weird bug with fireworks not showing every second or so i'd say.
58+
// This ensures it stays constant to avoid random stutters
59+
private var shouldHaveFirework = false
60+
private val stillTickTimer = TickTimer()
4561

4662
init {
4763
listen<TickEvent.Pre> {
64+
shouldHaveFirework = shouldHaveFirework or player.hasFirework
4865
if (!player.isGliding) return@listen
49-
if (fireworkTimer.timePassed(lastDuration.seconds)) {
50-
findFirework()?.let {
51-
lastDuration = (it.get(DataComponentTypes.FIREWORKS)?.flightDuration ?: 1) * 0.5 + 0.5
52-
startFirework(inventory)
53-
fireworkTimer.reset()
54-
}
55-
}
5666

5767
var vec = Vec3d.ZERO
5868
val yaw = player.yaw
@@ -62,7 +72,29 @@ class GrimControlElytraFly(override val c: Config) : ElytraFlyMode(FlyMode.GrimC
6272
if (mc.options.rightKey.isPressed) vec = vec.add(Vec3d.fromPolar(0f, yaw + 90f))
6373
if (mc.options.jumpKey.isPressed) vec = vec.add(Vec3d(0.0, 1.0, 0.0))
6474
if (mc.options.sneakKey.isPressed) vec = vec.add(Vec3d(0.0, -1.0, 0.0))
65-
if (vec.lengthSquared() < 1e-4 && player.hasFirework) {
75+
76+
still = vec.lengthSquared() < 1e-4
77+
if (still) moving = false
78+
79+
if (still) {
80+
stillTickTimer.tick()
81+
if (!player.hasFirework) shouldHaveFirework = false
82+
if (noFlipFlop) return@listen
83+
} else {
84+
val firework = findFirework()
85+
if (fireworkTimer.timePassed(lastDuration.seconds - safetyMargin.seconds)) {
86+
if (firework == null) shouldHaveFirework = false
87+
else {
88+
lastDuration = (firework.get(DataComponentTypes.FIREWORKS)?.flightDuration ?: 1) * 0.5 + 0.5
89+
startFirework(inventory)
90+
fireworkTimer.reset()
91+
}
92+
}
93+
}
94+
95+
if (!shouldHaveFirework) return@listen
96+
97+
if (still) {
6698
if (flipFlop) {
6799
flipFlop = false
68100
rotationRequest { rotation(0f, 0f) }
@@ -71,10 +103,28 @@ class GrimControlElytraFly(override val c: Config) : ElytraFlyMode(FlyMode.GrimC
71103
rotationRequest { rotation(180f, 0f) }
72104
}
73105
} else {
106+
moving = true
74107
val rot = vec.yawAndPitch
75108
rotationRequest { rotation(rot.y, rot.x) }
76109
}.submit()
77110
}
111+
112+
listen<PlayerPacketEvent.Send> { event ->
113+
if (!player.isGliding || !noFlipFlop) return@listen
114+
val rot = RotationManager.activeRotation
115+
val flipFlop = rotFlipFlop.toFloat() * 0.001f
116+
rotFlipFlop = !rotFlipFlop
117+
event.packet = PlayerMoveC2SPacket.Full(player.pos, rot.yawF + flipFlop, rot.pitchF, player.isOnGround, player.horizontalCollision)
118+
}
119+
120+
listen<PacketEvent.Send.Pre> { event ->
121+
if (event.packet !is PlayerMoveC2SPacket || !player.isGliding || !noFlipFlop || !still) return@listen
122+
if (stillTickTimer.hasSurpassed(packetGap)) {
123+
stillTickTimer.reset()
124+
return@listen
125+
}
126+
event.cancel()
127+
}
78128
}
79129

80130
private fun SafeContext.findFirework(): ItemStack? {

src/main/kotlin/com/lambda/module/modules/player/InventoryMove.kt

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.lambda.interaction.managers.rotating.IRotationRequest.Companion.rotat
2626
import com.lambda.interaction.managers.rotating.RotationMode
2727
import com.lambda.module.Module
2828
import com.lambda.module.tag.ModuleTag
29+
import com.lambda.util.InputUtils
2930
import com.lambda.util.InputUtils.isKeyPressed
3031
import com.lambda.util.math.MathUtils.toFloatSign
3132
import net.minecraft.client.gui.screen.ChatScreen
@@ -84,17 +85,7 @@ object InventoryMove : Module(
8485
}
8586

8687
@JvmStatic
87-
fun isKeyMovementRelated(key: Int): Boolean {
88-
val options = mc.options
89-
return when (key) {
90-
options.forwardKey.boundKey.code,
91-
options.backKey.boundKey.code,
92-
options.leftKey.boundKey.code,
93-
options.rightKey.boundKey.code,
94-
options.jumpKey.boundKey.code,
95-
options.sprintKey.boundKey.code -> true
96-
options.sneakKey.boundKey.code if (!disableSneak) -> true
97-
else -> false
98-
}
99-
}
88+
fun isKeyMovementRelated(key: Int) =
89+
if (key == mc.options.sneakKey.boundKey.code && disableSneak) false
90+
else InputUtils.isKeyMovementRelated(key)
10091
}

src/main/kotlin/com/lambda/util/InputUtils.kt

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ import org.lwjgl.glfw.GLFW.glfwGetMouseButton
4040
object InputUtils {
4141
private val lastPressedKeys = Int2IntArrayMap() // Keep track of the previously pressed keys to report GLFW_RELEASE states
4242

43+
private val Int.pressedOrRepeated
44+
get() = this == 1 || this == 2
45+
46+
private val keys = KeyCode.entries.map { it.code }.filter { it > 0 }
47+
private val scancodes = keys.associateWith { GLFW.glfwGetKeyScancode(it) }
48+
49+
private val mouses = GLFW_MOUSE_BUTTON_1..GLFW_MOUSE_BUTTON_8
50+
51+
private val modMap = mapOf(
52+
GLFW_KEY_LEFT_SHIFT to 0x1,
53+
GLFW_KEY_RIGHT_SHIFT to 0x1,
54+
GLFW_KEY_LEFT_CONTROL to 0x2,
55+
GLFW_KEY_RIGHT_CONTROL to 0x2,
56+
GLFW_KEY_LEFT_ALT to 0x4,
57+
GLFW_KEY_RIGHT_ALT to 0x4,
58+
GLFW_KEY_LEFT_SUPER to 0x8,
59+
GLFW_KEY_RIGHT_SUPER to 0x8,
60+
)
61+
4362
/**
4463
* Returns whether any of the key-codes (not scan-codes) are being pressed
4564
*/
@@ -90,22 +109,18 @@ object InputUtils {
90109
(mouse == -1 || glfwGetMouseButton(mc.window.handle, mouse).pressedOrRepeated) &&
91110
trueMods.all { glfwGetKey(mc.window.handle, it.code).pressedOrRepeated }
92111

93-
private val Int.pressedOrRepeated
94-
get() = this == 1 || this == 2
95-
96-
private val keys = KeyCode.entries.map { it.code }.filter { it > 0 }
97-
private val scancodes = keys.associateWith { GLFW.glfwGetKeyScancode(it) }
98-
99-
private val mouses = GLFW_MOUSE_BUTTON_1..GLFW_MOUSE_BUTTON_8
100-
101-
private val modMap = mapOf(
102-
GLFW_KEY_LEFT_SHIFT to 0x1,
103-
GLFW_KEY_RIGHT_SHIFT to 0x1,
104-
GLFW_KEY_LEFT_CONTROL to 0x2,
105-
GLFW_KEY_RIGHT_CONTROL to 0x2,
106-
GLFW_KEY_LEFT_ALT to 0x4,
107-
GLFW_KEY_RIGHT_ALT to 0x4,
108-
GLFW_KEY_LEFT_SUPER to 0x8,
109-
GLFW_KEY_RIGHT_SUPER to 0x8,
110-
)
112+
@JvmStatic
113+
fun isKeyMovementRelated(key: Int): Boolean {
114+
val options = mc.options
115+
return when (key) {
116+
options.forwardKey.boundKey.code,
117+
options.backKey.boundKey.code,
118+
options.leftKey.boundKey.code,
119+
options.rightKey.boundKey.code,
120+
options.jumpKey.boundKey.code,
121+
options.sprintKey.boundKey.code,
122+
options.sneakKey.boundKey.code -> true
123+
else -> false
124+
}
125+
}
111126
}

0 commit comments

Comments
 (0)