From 9fe29244629386a676ed0e448754c1b6dc888c8f Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 28 Sep 2025 22:44:47 +0200 Subject: [PATCH 01/16] Add BetterFirework Module --- .../lambda/mixin/MinecraftClientMixin.java | 15 ++ .../module/modules/movement/BetterFirework.kt | 179 ++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt diff --git a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index cd94a75d8..0714ce34a 100644 --- a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -24,6 +24,7 @@ import com.lambda.event.events.TickEvent; import com.lambda.gui.DearImGui; import com.lambda.gui.components.ClickGuiLayout; +import com.lambda.module.modules.movement.BetterFirework; import com.lambda.module.modules.player.Interact; import com.lambda.module.modules.player.InventoryMove; import com.lambda.module.modules.player.PacketMine; @@ -189,6 +190,20 @@ void injectFastPlace(CallbackInfo ci) { itemUseCooldown = Interact.getPlaceDelay(); } + @Inject(method = "doItemUse", at = @At(value = "HEAD"), cancellable = true) + void injectItemUse(CallbackInfo ci) { + if (!BetterFirework.INSTANCE.isEnabled()) return; + + if (BetterFirework.INSTANCE.onInteract()) ci.cancel(); + } + + @Inject(method = "doItemPick", at = @At(value = "HEAD"), cancellable = true) + void injectItemPick(CallbackInfo ci) { + if (!BetterFirework.INSTANCE.isEnabled()) return; + + if (BetterFirework.INSTANCE.onPick()) ci.cancel(); + } + @WrapMethod(method = "getTargetMillisPerTick") float getTargetMillisPerTick(float millis, Operation original) { var length = TimerManager.INSTANCE.getLength(); diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt new file mode 100644 index 000000000..75dbf6077 --- /dev/null +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2025 Lambda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.lambda.module.modules.movement + +import com.lambda.context.SafeContext +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag +import com.lambda.threading.runSafe +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket +import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket +import net.minecraft.screen.PlayerScreenHandler +import net.minecraft.screen.slot.SlotActionType +import net.minecraft.util.Hand +import net.minecraft.util.hit.HitResult + +object BetterFirework : Module( + name = "BetterFirework", + description = "Improves firework usage", + tag = ModuleTag.MOVEMENT, +) { + private var autoTakeoff by setting("Auto Takeoff", true) + private var silent by setting("Silent", true) + private var swing by setting("Swing ", true) + private var middleClick by setting("Middle click", true) + private var middleClickCancel by setting("Middle Click Cancel", false, visibility = { middleClick }) + + private var state = BetterFireworkState.IDLE + private var openDelay = 0 + + init { + listen { + if (openDelay > 0) { + openDelay-- + if (openDelay == 0 && state == BetterFireworkState.WAIT_AIRBORNE) { + state = BetterFireworkState.IDLE + startFlying() + } + } + } + } + + fun onInteract(): Boolean { + if (!autoTakeoff) return false + + runSafe { + if (player.inventory.selectedStack?.item == Items.FIREWORK_ROCKET) { + if (mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS) { + return false + } + + mc.itemUseCooldown += 4 + return startFlying() + } + } + return false + } + + // Do on pick so mc does not select blocks on middle click after we start flying + fun onPick() = + runSafe { + if (!middleClick) return false + if (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) { + return false + } + if (player.isGliding) { + startFirework(silent) + } else { + startFlying() + } + return true + } ?: false // Edouardo: :3333333 + + fun SafeContext.startFlying(): Boolean { + if (player.isOnGround) { + state = BetterFireworkState.WAIT_AIRBORNE + player.jump() + openDelay = 1; // Magic number + return true + } + + if (player.isGliding) return false + + if (canOpenElytra(player)) { + connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) + startFirework(silent) + return true + } + + return false + } + + fun canOpenElytra(player: ClientPlayerEntity): Boolean { + return !player.abilities.flying && !player.hasVehicle() && !player.isClimbing && player.checkGliding() + } + + fun SafeContext.sendSwing() { + if (swing) { + player.swingHand(Hand.MAIN_HAND) + } else { + connection.sendPacket(HandSwingC2SPacket(Hand.MAIN_HAND)) + } + } + + fun SafeContext.startFirework(silent: Boolean): Boolean { + val fireworkSlot = getFireworkAtHotbar() + if (fireworkSlot != -1) { + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(fireworkSlot)) + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) + sendSwing() + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) + return true + } else if (silent) { + val fireworkIndex = getFireworkInInventoryScreen() + if (fireworkIndex != -1) { + interaction.clickSlot(player.playerScreenHandler.syncId, fireworkIndex, 0, SlotActionType.SWAP, mc.player) + + if (player.getInventory().selectedSlot != 0) { + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(0)) + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) + sendSwing() + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) + } else { + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.getYaw(), player.getPitch())) + sendSwing() + } + + interaction.clickSlot(player.playerScreenHandler.syncId, fireworkIndex, 0, SlotActionType.SWAP, mc.player) + return true + } + } + return false + } + + private fun SafeContext.getFireworkAtHotbar(): Int { + for (i in 0..8) { + val itemStack: ItemStack = player.getInventory().getStack(i) + if (itemStack.item !== Items.FIREWORK_ROCKET) continue + return i + } + return -1 + } + + private fun SafeContext.getFireworkInInventoryScreen(): Int { + val screenHandler: PlayerScreenHandler = player.playerScreenHandler + for (i in PlayerScreenHandler.INVENTORY_START.. Date: Sun, 28 Sep 2025 23:27:02 +0200 Subject: [PATCH 02/16] Refactor BetterFirework settings and some code --- .../module/modules/movement/BetterFirework.kt | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 75dbf6077..ab284050d 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -37,47 +37,52 @@ import net.minecraft.util.hit.HitResult object BetterFirework : Module( name = "BetterFirework", - description = "Improves firework usage", + description = "Automatic takeoff with fireworks", tag = ModuleTag.MOVEMENT, ) { - private var autoTakeoff by setting("Auto Takeoff", true) - private var silent by setting("Silent", true) - private var swing by setting("Swing ", true) - private var middleClick by setting("Middle click", true) - private var middleClickCancel by setting("Middle Click Cancel", false, visibility = { middleClick }) + private var fireworkInteract by setting("Firework Interact", true, "Automatically start flying when right clicking fireworks") + private var fireworkInteractCancel by setting("Firework Interact Cancel", false, "Cancel block interactions while holding fireworks", visibility = { fireworkInteract }) + private var middleClick by setting("Middle Click", true, "Use firework on middle mouse click") + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click", visibility = { middleClick }) + private var clientSwing by setting("Swing", true, "Swing hand client side") + private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory", visibility = { middleClick }) - private var state = BetterFireworkState.IDLE private var openDelay = 0 init { listen { + // Try opening the elytra after a delay after jumping if (openDelay > 0) { openDelay-- - if (openDelay == 0 && state == BetterFireworkState.WAIT_AIRBORNE) { - state = BetterFireworkState.IDLE - startFlying() + if (openDelay == 0) { + tryTakeoff() } } } } - fun onInteract(): Boolean { - if (!autoTakeoff) return false - + /** + * Returns true if the mc item interaction should be canceled + */ + fun onInteract() = runSafe { - if (player.inventory.selectedStack?.item == Items.FIREWORK_ROCKET) { - if (mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS) { - return false - } - - mc.itemUseCooldown += 4 - return startFlying() + if (!fireworkInteract) return false + if (player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET) { + return false } - } - return false - } + if (player.isGliding) { + return false // No need to do special magic if we are already holding fireworks and flying + } + if (mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel) { + return false + } + mc.itemUseCooldown += 4 + return tryTakeoff() || fireworkInteractCancel + } ?: false - // Do on pick so mc does not select blocks on middle click after we start flying + /** + * Returns true when the pick interaction should be canceled. + */ fun onPick() = runSafe { if (!middleClick) return false @@ -85,26 +90,30 @@ object BetterFirework : Module( return false } if (player.isGliding) { - startFirework(silent) + // If already gliding use another firework + startFirework(silentUse) } else { - startFlying() + tryTakeoff() } return true } ?: false // Edouardo: :3333333 - fun SafeContext.startFlying(): Boolean { + /** + * This function prepares takeoff from standing or falling. + * If the player is standing on ground it jumps to prepare for takeoff and return true. + * If the player is falling it opens the elytra, uses a firework and return true. + * Otherwise, return false and does nothing. + */ + fun SafeContext.tryTakeoff(): Boolean { if (player.isOnGround) { - state = BetterFireworkState.WAIT_AIRBORNE player.jump() - openDelay = 1; // Magic number + openDelay = 1; // Magic number, works on 2b so we GUCCI return true } - if (player.isGliding) return false - if (canOpenElytra(player)) { connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) - startFirework(silent) + startFirework(silentUse) return true } @@ -116,13 +125,17 @@ object BetterFirework : Module( } fun SafeContext.sendSwing() { - if (swing) { + if (clientSwing) { player.swingHand(Hand.MAIN_HAND) } else { connection.sendPacket(HandSwingC2SPacket(Hand.MAIN_HAND)) } } + /** + * Use a firework from the hotbar or inventory if possible. + * Return true if a firework has been used + */ fun SafeContext.startFirework(silent: Boolean): Boolean { val fireworkSlot = getFireworkAtHotbar() if (fireworkSlot != -1) { @@ -171,9 +184,4 @@ object BetterFirework : Module( } return -1 } - - enum class BetterFireworkState { - IDLE, - WAIT_AIRBORNE - } } \ No newline at end of file From 2e9dda1c5dab2689c31672990912930945b03891 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Tue, 14 Oct 2025 17:28:23 +0200 Subject: [PATCH 03/16] Update logic handling in BetterFirework.kt --- .../module/modules/movement/BetterFirework.kt | 76 ++++++++++--------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index ab284050d..5ce15f475 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -24,6 +24,7 @@ import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket @@ -47,15 +48,25 @@ object BetterFirework : Module( private var clientSwing by setting("Swing", true, "Swing hand client side") private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory", visibility = { middleClick }) - private var openDelay = 0 + private var takeoffState = TakeoffState.NONE init { listen { - // Try opening the elytra after a delay after jumping - if (openDelay > 0) { - openDelay-- - if (openDelay == 0) { - tryTakeoff() + when (takeoffState) { + TakeoffState.NONE -> { + // Nothing to do + } + TakeoffState.JUMPING -> { + player.jump() + takeoffState = TakeoffState.START_FLYING + } + TakeoffState.START_FLYING -> { + if (player.canOpenElytra) { + player.startGliding() + connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) + } + startFirework(silentUse) + takeoffState = TakeoffState.NONE } } } @@ -77,7 +88,13 @@ object BetterFirework : Module( return false } mc.itemUseCooldown += 4 - return tryTakeoff() || fireworkInteractCancel + val cancelInteract = player.canTakeoff || fireworkInteractCancel + if (player.canTakeoff) { + takeoffState = TakeoffState.JUMPING + } else if (player.canOpenElytra) { + takeoffState = TakeoffState.START_FLYING + } + return cancelInteract } ?: false /** @@ -89,40 +106,23 @@ object BetterFirework : Module( if (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) { return false } - if (player.isGliding) { + if (takeoffState != TakeoffState.NONE) { + return false // Prevent using multiple times + } + if (player.canOpenElytra || player.isGliding) { // If already gliding use another firework - startFirework(silentUse) - } else { - tryTakeoff() + takeoffState = TakeoffState.START_FLYING + } else if (player.canTakeoff) { + takeoffState = TakeoffState.JUMPING } return true } ?: false // Edouardo: :3333333 - /** - * This function prepares takeoff from standing or falling. - * If the player is standing on ground it jumps to prepare for takeoff and return true. - * If the player is falling it opens the elytra, uses a firework and return true. - * Otherwise, return false and does nothing. - */ - fun SafeContext.tryTakeoff(): Boolean { - if (player.isOnGround) { - player.jump() - openDelay = 1; // Magic number, works on 2b so we GUCCI - return true - } - - if (canOpenElytra(player)) { - connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) - startFirework(silentUse) - return true - } + val ClientPlayerEntity.canTakeoff: Boolean + get() = isOnGround || canOpenElytra - return false - } - - fun canOpenElytra(player: ClientPlayerEntity): Boolean { - return !player.abilities.flying && !player.hasVehicle() && !player.isClimbing && player.checkGliding() - } + val ClientPlayerEntity.canOpenElytra: Boolean + get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION) fun SafeContext.sendSwing() { if (clientSwing) { @@ -184,4 +184,10 @@ object BetterFirework : Module( } return -1 } + + enum class TakeoffState { + NONE, + JUMPING, + START_FLYING + } } \ No newline at end of file From 10f1127ace5279ed35efecefbba5e744e4ca1f29 Mon Sep 17 00:00:00 2001 From: Edouard127 <46357922+Edouard127@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:59:23 -0400 Subject: [PATCH 04/16] Nits --- .../lambda/mixin/MinecraftClientMixin.java | 18 ++-- .../module/modules/movement/BetterFirework.kt | 95 +++++++++---------- 2 files changed, 54 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java index 0714ce34a..0526bab37 100644 --- a/src/main/java/com/lambda/mixin/MinecraftClientMixin.java +++ b/src/main/java/com/lambda/mixin/MinecraftClientMixin.java @@ -190,18 +190,16 @@ void injectFastPlace(CallbackInfo ci) { itemUseCooldown = Interact.getPlaceDelay(); } - @Inject(method = "doItemUse", at = @At(value = "HEAD"), cancellable = true) - void injectItemUse(CallbackInfo ci) { - if (!BetterFirework.INSTANCE.isEnabled()) return; - - if (BetterFirework.INSTANCE.onInteract()) ci.cancel(); + @WrapMethod(method = "doItemUse") + void injectItemUse(Operation original) { + if (BetterFirework.INSTANCE.isDisabled() || !BetterFirework.onInteract()) + original.call(); } - @Inject(method = "doItemPick", at = @At(value = "HEAD"), cancellable = true) - void injectItemPick(CallbackInfo ci) { - if (!BetterFirework.INSTANCE.isEnabled()) return; - - if (BetterFirework.INSTANCE.onPick()) ci.cancel(); + @WrapMethod(method = "doItemPick") + void injectItemPick(Operation original) { + if (BetterFirework.INSTANCE.isDisabled() || !BetterFirework.onPick()) + original.call(); } @WrapMethod(method = "getTargetMillisPerTick") diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 5ce15f475..4176f43f4 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -20,18 +20,19 @@ package com.lambda.module.modules.movement import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +import com.lambda.util.player.SlotUtils.hotbar +import com.lambda.util.player.SlotUtils.storage import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.effect.StatusEffects -import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket -import net.minecraft.screen.PlayerScreenHandler import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult @@ -42,24 +43,32 @@ object BetterFirework : Module( tag = ModuleTag.MOVEMENT, ) { private var fireworkInteract by setting("Firework Interact", true, "Automatically start flying when right clicking fireworks") - private var fireworkInteractCancel by setting("Firework Interact Cancel", false, "Cancel block interactions while holding fireworks", visibility = { fireworkInteract }) + private var fireworkInteractCancel by setting("Firework Interact Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } + private var middleClick by setting("Middle Click", true, "Use firework on middle mouse click") - private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click", visibility = { middleClick }) + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { middleClick } + private var clientSwing by setting("Swing", true, "Swing hand client side") - private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory", visibility = { middleClick }) + private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { middleClick } private var takeoffState = TakeoffState.NONE + val ClientPlayerEntity.canTakeoff: Boolean + get() = isOnGround || canOpenElytra + + val ClientPlayerEntity.canOpenElytra: Boolean + get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION) + init { listen { when (takeoffState) { - TakeoffState.NONE -> { - // Nothing to do - } + TakeoffState.NONE -> {} + TakeoffState.JUMPING -> { player.jump() takeoffState = TakeoffState.START_FLYING } + TakeoffState.START_FLYING -> { if (player.canOpenElytra) { player.startGliding() @@ -75,6 +84,7 @@ object BetterFirework : Module( /** * Returns true if the mc item interaction should be canceled */ + @JvmStatic fun onInteract() = runSafe { if (!fireworkInteract) return false @@ -100,6 +110,7 @@ object BetterFirework : Module( /** * Returns true when the pick interaction should be canceled. */ + @JvmStatic fun onPick() = runSafe { if (!middleClick) return false @@ -116,13 +127,7 @@ object BetterFirework : Module( takeoffState = TakeoffState.JUMPING } return true - } ?: false // Edouardo: :3333333 - - val ClientPlayerEntity.canTakeoff: Boolean - get() = isOnGround || canOpenElytra - - val ClientPlayerEntity.canOpenElytra: Boolean - get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION) + } ?: false fun SafeContext.sendSwing() { if (clientSwing) { @@ -137,17 +142,27 @@ object BetterFirework : Module( * Return true if a firework has been used */ fun SafeContext.startFirework(silent: Boolean): Boolean { - val fireworkSlot = getFireworkAtHotbar() - if (fireworkSlot != -1) { - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(fireworkSlot)) - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) - sendSwing() - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) - return true - } else if (silent) { - val fireworkIndex = getFireworkInInventoryScreen() - if (fireworkIndex != -1) { - interaction.clickSlot(player.playerScreenHandler.syncId, fireworkIndex, 0, SlotActionType.SWAP, mc.player) + val stack = selectStack(count = 1) { isItem(Items.FIREWORK_ROCKET) } + + stack.bestItemMatch(player.hotbar) + ?.let { + val swap = player.hotbar.indexOf(it) + + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(swap)) + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) + sendSwing() + player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) + + return true + } + + if (!silent) return false + + stack.bestItemMatch(player.storage) + ?.let { + val swap = player.storage.indexOf(it) + + interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) if (player.getInventory().selectedSlot != 0) { player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(0)) @@ -155,34 +170,16 @@ object BetterFirework : Module( sendSwing() player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) } else { - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.getYaw(), player.getPitch())) + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) sendSwing() } - interaction.clickSlot(player.playerScreenHandler.syncId, fireworkIndex, 0, SlotActionType.SWAP, mc.player) + interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) + return true } - } - return false - } - private fun SafeContext.getFireworkAtHotbar(): Int { - for (i in 0..8) { - val itemStack: ItemStack = player.getInventory().getStack(i) - if (itemStack.item !== Items.FIREWORK_ROCKET) continue - return i - } - return -1 - } - - private fun SafeContext.getFireworkInInventoryScreen(): Int { - val screenHandler: PlayerScreenHandler = player.playerScreenHandler - for (i in PlayerScreenHandler.INVENTORY_START.. Date: Sat, 1 Nov 2025 22:33:01 +0100 Subject: [PATCH 05/16] Use HotbarManager to swap to firework slots --- .../lambda/config/groups/HotbarSettings.kt | 3 +- .../module/modules/movement/BetterFirework.kt | 51 +++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt b/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt index 11c9bd66c..5558d3ec1 100644 --- a/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt +++ b/src/main/kotlin/com/lambda/config/groups/HotbarSettings.kt @@ -18,6 +18,7 @@ package com.lambda.config.groups import com.lambda.config.Configurable +import com.lambda.event.Event import com.lambda.event.events.TickEvent import com.lambda.interaction.request.hotbar.HotbarConfig import com.lambda.util.NamedEnum @@ -31,5 +32,5 @@ class HotbarSettings( override val swapDelay by c.setting("Swap Delay", 0, 0..3, 1, "The number of ticks delay before allowing another hotbar selection swap", " ticks", visibility = vis).group(baseGroup) override val swapsPerTick by c.setting("Swaps Per Tick", 3, 1..10, 1, "The number of hotbar selection swaps that can take place each tick") { swapDelay <= 0 && vis() }.group(baseGroup) override val swapPause by c.setting("Swap Pause", 0, 0..20, 1, "The delay in ticks to pause actions after switching to the slot", " ticks", visibility = vis).group(baseGroup) - override val sequenceStageMask by c.setting("Hotbar Stage Mask", setOf(TickEvent.Input.Post), description = "The sub-tick timing at which hotbar actions are performed", visibility = vis).group(baseGroup) + override val sequenceStageMask by c.setting("Hotbar Stage Mask", setOf(TickEvent.Input.Post), description = "The sub-tick timing at which hotbar actions are performed", visibility = vis).group(baseGroup) } \ No newline at end of file diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 4176f43f4..617ddbce5 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -17,14 +17,21 @@ package com.lambda.module.modules.movement +import com.lambda.config.groups.HotbarSettings +import com.lambda.config.settings.collections.SetSetting.Companion.immutableSet import com.lambda.context.SafeContext import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack +import com.lambda.interaction.request.hotbar.HotbarManager +import com.lambda.interaction.request.hotbar.HotbarRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +import com.lambda.util.Communication.warn +import com.lambda.util.NamedEnum import com.lambda.util.player.SlotUtils.hotbar +import com.lambda.util.player.SlotUtils.hotbarAndStorage import com.lambda.util.player.SlotUtils.storage import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.effect.StatusEffects @@ -42,14 +49,22 @@ object BetterFirework : Module( description = "Automatic takeoff with fireworks", tag = ModuleTag.MOVEMENT, ) { - private var fireworkInteract by setting("Firework Interact", true, "Automatically start flying when right clicking fireworks") - private var fireworkInteractCancel by setting("Firework Interact Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } + private var middleClick by setting("Middle Click", true, "Use firework on middle mouse click").group(Group.General) + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { middleClick }.group(Group.General) + private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") + private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } - private var middleClick by setting("Middle Click", true, "Use firework on middle mouse click") - private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { middleClick } + private var clientSwing by setting("Swing", true, "Swing hand client side").group(Group.General) + private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { middleClick }.group(Group.General) - private var clientSwing by setting("Swing", true, "Swing hand client side") - private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { middleClick } + override val hotbarConfig = HotbarSettings(this, Group.Hotbar).apply { + ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } + } + + private enum class Group(override val displayName: String) : NamedEnum { + General("General"), + Hotbar("Hotbar") + } private var takeoffState = TakeoffState.NONE @@ -146,36 +161,30 @@ object BetterFirework : Module( stack.bestItemMatch(player.hotbar) ?.let { - val swap = player.hotbar.indexOf(it) - - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(swap)) - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) - sendSwing() - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) + val request = HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) + if (request.done) { + player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) + sendSwing() + } return true } if (!silent) return false - stack.bestItemMatch(player.storage) + stack.bestItemMatch(player.hotbarAndStorage) ?.let { - val swap = player.storage.indexOf(it) + val swap = player.hotbarAndStorage.indexOf(it) interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) - if (player.getInventory().selectedSlot != 0) { - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(0)) - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) - sendSwing() - player.networkHandler.sendPacket(UpdateSelectedSlotC2SPacket(player.getInventory().selectedSlot)) - } else { + val request = HotbarManager.request(HotbarRequest(0, this@BetterFirework, keepTicks = 0)) + if (request.done) { player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) sendSwing() } interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) - return true } From 903aff19a05dd8e70183786222cae10c4695d948 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:34:16 +0100 Subject: [PATCH 06/16] Change enums to Camel case --- .../module/modules/movement/BetterFirework.kt | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 617ddbce5..09b3dcaa4 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -28,18 +28,15 @@ import com.lambda.interaction.request.hotbar.HotbarRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import com.lambda.util.Communication.warn import com.lambda.util.NamedEnum import com.lambda.util.player.SlotUtils.hotbar import com.lambda.util.player.SlotUtils.hotbarAndStorage -import com.lambda.util.player.SlotUtils.storage import net.minecraft.client.network.ClientPlayerEntity import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket -import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult @@ -66,7 +63,7 @@ object BetterFirework : Module( Hotbar("Hotbar") } - private var takeoffState = TakeoffState.NONE + private var takeoffState = TakeoffState.None val ClientPlayerEntity.canTakeoff: Boolean get() = isOnGround || canOpenElytra @@ -77,20 +74,20 @@ object BetterFirework : Module( init { listen { when (takeoffState) { - TakeoffState.NONE -> {} + TakeoffState.None -> {} - TakeoffState.JUMPING -> { + TakeoffState.Jumping -> { player.jump() - takeoffState = TakeoffState.START_FLYING + takeoffState = TakeoffState.StartFlying } - TakeoffState.START_FLYING -> { + TakeoffState.StartFlying -> { if (player.canOpenElytra) { player.startGliding() connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) } startFirework(silentUse) - takeoffState = TakeoffState.NONE + takeoffState = TakeoffState.None } } } @@ -115,9 +112,9 @@ object BetterFirework : Module( mc.itemUseCooldown += 4 val cancelInteract = player.canTakeoff || fireworkInteractCancel if (player.canTakeoff) { - takeoffState = TakeoffState.JUMPING + takeoffState = TakeoffState.Jumping } else if (player.canOpenElytra) { - takeoffState = TakeoffState.START_FLYING + takeoffState = TakeoffState.StartFlying } return cancelInteract } ?: false @@ -132,14 +129,14 @@ object BetterFirework : Module( if (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) { return false } - if (takeoffState != TakeoffState.NONE) { + if (takeoffState != TakeoffState.None) { return false // Prevent using multiple times } if (player.canOpenElytra || player.isGliding) { // If already gliding use another firework - takeoffState = TakeoffState.START_FLYING + takeoffState = TakeoffState.StartFlying } else if (player.canTakeoff) { - takeoffState = TakeoffState.JUMPING + takeoffState = TakeoffState.Jumping } return true } ?: false @@ -192,8 +189,8 @@ object BetterFirework : Module( } enum class TakeoffState { - NONE, - JUMPING, - START_FLYING + None, + Jumping, + StartFlying } } From 99a3940e41a04d19cb334694f00e9c8dc754146e Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 2 Nov 2025 16:07:31 +0100 Subject: [PATCH 07/16] Add Universal Keybind to BetterFirework.kt --- .../config/settings/complex/KeybindSetting.kt | 6 ++ .../module/modules/movement/BetterFirework.kt | 55 +++++++++++++++++-- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt b/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt index a4b232031..e651ff463 100644 --- a/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt +++ b/src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt @@ -174,6 +174,12 @@ data class Bind( if (modifiers and GLFW_MOD_NUM_LOCK != 0) add(KeyCode.NUM_LOCK) } + val isMouseBind: Boolean + get() = mouse >= 0 + + val isKeyBind: Boolean + get() = key > 0 + val name: String get() { if (mouse < 0 && modifiers <= 0 && key <= 0) return "Unbound" diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 09b3dcaa4..8ec3a42e9 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -19,7 +19,10 @@ package com.lambda.module.modules.movement import com.lambda.config.groups.HotbarSettings import com.lambda.config.settings.collections.SetSetting.Companion.immutableSet +import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext +import com.lambda.event.events.KeyboardEvent +import com.lambda.event.events.MouseEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack @@ -28,10 +31,13 @@ import com.lambda.interaction.request.hotbar.HotbarRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe +import com.lambda.util.KeyCode +import com.lambda.util.Mouse import com.lambda.util.NamedEnum import com.lambda.util.player.SlotUtils.hotbar import com.lambda.util.player.SlotUtils.hotbarAndStorage import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.client.option.KeyBinding import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket @@ -40,19 +46,20 @@ import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult +import org.lwjgl.glfw.GLFW object BetterFirework : Module( name = "BetterFirework", description = "Automatic takeoff with fireworks", tag = ModuleTag.MOVEMENT, ) { - private var middleClick by setting("Middle Click", true, "Use firework on middle mouse click").group(Group.General) - private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { middleClick }.group(Group.General) + private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework").group(Group.General) + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.UNBOUND.code }.group(Group.General) private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } private var clientSwing by setting("Swing", true, "Swing hand client side").group(Group.General) - private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { middleClick }.group(Group.General) + private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { activateButton.key != KeyCode.UNBOUND.code }.group(Group.General) override val hotbarConfig = HotbarSettings(this, Group.Hotbar).apply { ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } @@ -91,6 +98,42 @@ object BetterFirework : Module( } } } + listen { + if (!activateButton.isMouseBind || activateButton.mouse == mc.options.pickItemKey.boundKey.code) { + return@listen + } + if (it.isPressed && it.satisfies(activateButton)) { + runSafe { + if (takeoffState != TakeoffState.None) { + return@listen // Prevent using multiple times + } + if (player.canOpenElytra || player.isGliding) { + // If already gliding use another firework + takeoffState = TakeoffState.StartFlying + } else if (player.canTakeoff) { + takeoffState = TakeoffState.Jumping + } + } + } + } + listen { + if (!activateButton.isKeyBind || activateButton.key == mc.options.pickItemKey.boundKey.code) { + return@listen + } + if (it.isPressed && it.satisfies(activateButton)) { + runSafe { + if (takeoffState != TakeoffState.None) { + return@listen // Prevent using multiple times + } + if (player.canOpenElytra || player.isGliding) { + // If already gliding use another firework + takeoffState = TakeoffState.StartFlying + } else if (player.canTakeoff) { + takeoffState = TakeoffState.Jumping + } + } + } + } } /** @@ -125,10 +168,12 @@ object BetterFirework : Module( @JvmStatic fun onPick() = runSafe { - if (!middleClick) return false if (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) { return false } + if (!activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code) { + return false + } if (takeoffState != TakeoffState.None) { return false // Prevent using multiple times } @@ -138,7 +183,7 @@ object BetterFirework : Module( } else if (player.canTakeoff) { takeoffState = TakeoffState.Jumping } - return true + return middleClickCancel } ?: false fun SafeContext.sendSwing() { From 6aea73871bb6b91724eb1b9b8f1ba383280b6f91 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 2 Nov 2025 17:02:27 +0100 Subject: [PATCH 08/16] Simplify Keyboard and Mouse Event listener --- .../lambda/module/modules/movement/BetterFirework.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 8ec3a42e9..13c29776e 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -99,10 +99,10 @@ object BetterFirework : Module( } } listen { - if (!activateButton.isMouseBind || activateButton.mouse == mc.options.pickItemKey.boundKey.code) { - return@listen - } if (it.isPressed && it.satisfies(activateButton)) { + if (activateButton.mouse == mc.options.pickItemKey.boundKey.code) { + return@listen + } runSafe { if (takeoffState != TakeoffState.None) { return@listen // Prevent using multiple times @@ -117,10 +117,10 @@ object BetterFirework : Module( } } listen { - if (!activateButton.isKeyBind || activateButton.key == mc.options.pickItemKey.boundKey.code) { - return@listen - } if (it.isPressed && it.satisfies(activateButton)) { + if (activateButton.key == mc.options.pickItemKey.boundKey.code) { + return@listen + } runSafe { if (takeoffState != TakeoffState.None) { return@listen // Prevent using multiple times From 052fdffad8e759226911f7fc1972f95f7706afa8 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:02:27 +0100 Subject: [PATCH 09/16] Update BetterFirework to use InventoryManager for inventory switching stuff --- .../module/modules/movement/BetterFirework.kt | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 13c29776e..f04028659 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -18,6 +18,7 @@ package com.lambda.module.modules.movement import com.lambda.config.groups.HotbarSettings +import com.lambda.config.groups.InventorySettings import com.lambda.config.settings.collections.SetSetting.Companion.immutableSet import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext @@ -28,6 +29,7 @@ import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack import com.lambda.interaction.request.hotbar.HotbarManager import com.lambda.interaction.request.hotbar.HotbarRequest +import com.lambda.interaction.request.inventory.InventoryRequest.Companion.inventoryRequest import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe @@ -37,7 +39,6 @@ import com.lambda.util.NamedEnum import com.lambda.util.player.SlotUtils.hotbar import com.lambda.util.player.SlotUtils.hotbarAndStorage import net.minecraft.client.network.ClientPlayerEntity -import net.minecraft.client.option.KeyBinding import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket @@ -46,7 +47,6 @@ import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult -import org.lwjgl.glfw.GLFW object BetterFirework : Module( name = "BetterFirework", @@ -54,20 +54,25 @@ object BetterFirework : Module( tag = ModuleTag.MOVEMENT, ) { private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework").group(Group.General) - private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.UNBOUND.code }.group(Group.General) + private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } private var clientSwing by setting("Swing", true, "Swing hand client side").group(Group.General) - private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { activateButton.key != KeyCode.UNBOUND.code }.group(Group.General) + private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) override val hotbarConfig = HotbarSettings(this, Group.Hotbar).apply { ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } } + override val inventoryConfig = InventorySettings(this, Group.Inventory).apply { + ::tickStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } + } + private enum class Group(override val displayName: String) : NamedEnum { General("General"), - Hotbar("Hotbar") + Hotbar("Hotbar"), + Inventory("Inventory") } private var takeoffState = TakeoffState.None @@ -198,39 +203,40 @@ object BetterFirework : Module( * Use a firework from the hotbar or inventory if possible. * Return true if a firework has been used */ - fun SafeContext.startFirework(silent: Boolean): Boolean { + fun SafeContext.startFirework(silent: Boolean) { val stack = selectStack(count = 1) { isItem(Items.FIREWORK_ROCKET) } stack.bestItemMatch(player.hotbar) ?.let { val request = HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) if (request.done) { - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) + interaction.interactItem(player, Hand.MAIN_HAND) sendSwing() } - return true + return } - if (!silent) return false + if (!silent) return stack.bestItemMatch(player.hotbarAndStorage) ?.let { - val swap = player.hotbarAndStorage.indexOf(it) - - interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) - - val request = HotbarManager.request(HotbarRequest(0, this@BetterFirework, keepTicks = 0)) - if (request.done) { - player.networkHandler.sendPacket(PlayerInteractItemC2SPacket(Hand.MAIN_HAND, 0, player.yaw, player.pitch)) - sendSwing() - } - - interaction.clickSlot(player.playerScreenHandler.syncId, swap, 0, SlotActionType.SWAP, mc.player) - return true + val swapSlotId = player.hotbarAndStorage.indexOf(it) + val hotbarSlotToSwapWith = player.hotbar.find { slot -> slot.isEmpty } ?.let { slot -> player.hotbar.indexOf(slot) } ?: 8 + + inventoryRequest { + swap(swapSlotId, hotbarSlotToSwapWith) + action { + HotbarManager.request(HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)) + .submit(queueIfClosed = false) + .done.let { + interaction.interactItem(player, Hand.MAIN_HAND) + sendSwing() + } + } + swap(swapSlotId, hotbarSlotToSwapWith) + }.submit() } - - return false } enum class TakeoffState { From 7996ec9fa09bcc99044f4bdacd0ca76c4ab4f038 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:07:15 +0100 Subject: [PATCH 10/16] Clean up code --- .../module/modules/movement/BetterFirework.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index f04028659..a86827177 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -208,12 +208,12 @@ object BetterFirework : Module( stack.bestItemMatch(player.hotbar) ?.let { - val request = HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) - if (request.done) { - interaction.interactItem(player, Hand.MAIN_HAND) - sendSwing() - } - + HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) + .done + .let { + interaction.interactItem(player, Hand.MAIN_HAND) + sendSwing() + } return } @@ -228,8 +228,8 @@ object BetterFirework : Module( swap(swapSlotId, hotbarSlotToSwapWith) action { HotbarManager.request(HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)) - .submit(queueIfClosed = false) - .done.let { + .done + .let { interaction.interactItem(player, Hand.MAIN_HAND) sendSwing() } From 060a7d99f3526b1ba1dee080f60a30e6af71fb49 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:31:57 +0100 Subject: [PATCH 11/16] Add mid-flight activation keybind --- .../module/modules/movement/BetterFirework.kt | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index a86827177..e48101d5e 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -24,6 +24,7 @@ import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext import com.lambda.event.events.KeyboardEvent import com.lambda.event.events.MouseEvent +import com.lambda.event.events.PlayerEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack @@ -54,6 +55,7 @@ object BetterFirework : Module( tag = ModuleTag.MOVEMENT, ) { private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework").group(Group.General) + private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind(0, 0, KeyCode.Unbound.code), "Firework use key for mid flight activation").group(Group.General) private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks") private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } @@ -104,7 +106,10 @@ object BetterFirework : Module( } } listen { - if (it.isPressed && it.satisfies(activateButton)) { + if (!it.isPressed) { + return@listen + } + if (it.satisfies(activateButton)) { if (activateButton.mouse == mc.options.pickItemKey.boundKey.code) { return@listen } @@ -120,22 +125,35 @@ object BetterFirework : Module( } } } + if (it.satisfies(midFlightActivationKey)) { + runSafe { + if (player.isGliding) + takeoffState = TakeoffState.StartFlying + } + } } listen { - if (it.isPressed && it.satisfies(activateButton)) { - if (activateButton.key == mc.options.pickItemKey.boundKey.code) { - return@listen + if (!it.isPressed) { + return@listen + } + if (it.satisfies(activateButton)) { + if (activateButton.key != mc.options.pickItemKey.boundKey.code) { + runSafe { + if (takeoffState == TakeoffState.None) { + if (player.canOpenElytra || player.isGliding) { + // If already gliding use another firework + takeoffState = TakeoffState.StartFlying + } else if (player.canTakeoff) { + takeoffState = TakeoffState.Jumping + } + } + } } + } + if (it.satisfies(midFlightActivationKey)) { runSafe { - if (takeoffState != TakeoffState.None) { - return@listen // Prevent using multiple times - } - if (player.canOpenElytra || player.isGliding) { - // If already gliding use another firework + if (player.isGliding) takeoffState = TakeoffState.StartFlying - } else if (player.canTakeoff) { - takeoffState = TakeoffState.Jumping - } } } } From d9bd0059a1d2cb05d03a7da34bcb96b190ef30c7 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:56:35 +0100 Subject: [PATCH 12/16] Update BetterFirework code --- .../module/modules/movement/BetterFirework.kt | 84 +++++++++---------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index e48101d5e..05e738f5c 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -165,24 +165,22 @@ object BetterFirework : Module( @JvmStatic fun onInteract() = runSafe { - if (!fireworkInteract) return false - if (player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET) { - return false - } - if (player.isGliding) { - return false // No need to do special magic if we are already holding fireworks and flying - } - if (mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel) { - return false - } - mc.itemUseCooldown += 4 - val cancelInteract = player.canTakeoff || fireworkInteractCancel - if (player.canTakeoff) { - takeoffState = TakeoffState.Jumping - } else if (player.canOpenElytra) { - takeoffState = TakeoffState.StartFlying + when { + !fireworkInteract -> false + player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET -> false + player.isGliding -> false // No need to do special magic if we are already holding fireworks and flying + mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel -> false + else -> { + mc.itemUseCooldown += 4 + val cancelInteract = player.canTakeoff || fireworkInteractCancel + if (player.canTakeoff) { + takeoffState = TakeoffState.Jumping + } else if (player.canOpenElytra) { + takeoffState = TakeoffState.StartFlying + } + cancelInteract + } } - return cancelInteract } ?: false /** @@ -191,22 +189,20 @@ object BetterFirework : Module( @JvmStatic fun onPick() = runSafe { - if (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) { - return false - } - if (!activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code) { - return false - } - if (takeoffState != TakeoffState.None) { - return false // Prevent using multiple times - } - if (player.canOpenElytra || player.isGliding) { - // If already gliding use another firework - takeoffState = TakeoffState.StartFlying - } else if (player.canTakeoff) { - takeoffState = TakeoffState.Jumping + when { + mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel -> false + !activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code -> false + takeoffState != TakeoffState.None -> false // Prevent using multiple times + else -> { + if (player.canOpenElytra || player.isGliding) { + // If already gliding use another firework + takeoffState = TakeoffState.StartFlying + } else if (player.canTakeoff) { + takeoffState = TakeoffState.Jumping + } + middleClickCancel + } } - return middleClickCancel } ?: false fun SafeContext.sendSwing() { @@ -226,12 +222,12 @@ object BetterFirework : Module( stack.bestItemMatch(player.hotbar) ?.let { - HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) - .done - .let { - interaction.interactItem(player, Hand.MAIN_HAND) - sendSwing() - } + val request = HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) + .submit(queueIfClosed = false) + if (request.done) { + interaction.interactItem(player, Hand.MAIN_HAND) + sendSwing() + } return } @@ -245,12 +241,12 @@ object BetterFirework : Module( inventoryRequest { swap(swapSlotId, hotbarSlotToSwapWith) action { - HotbarManager.request(HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)) - .done - .let { - interaction.interactItem(player, Hand.MAIN_HAND) - sendSwing() - } + val request = HotbarManager.request(HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)) + .submit(queueIfClosed = false) + if (request.done) { + interaction.interactItem(player, Hand.MAIN_HAND) + sendSwing() + } } swap(swapSlotId, hotbarSlotToSwapWith) }.submit() From 0d513e1a7a620346606f83e8ba6362c80b1a8e47 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Sun, 23 Nov 2025 18:57:03 +0100 Subject: [PATCH 13/16] Lint code --- .../com/lambda/module/modules/movement/BetterFirework.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 05e738f5c..cbb0ae418 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -24,7 +24,6 @@ import com.lambda.config.settings.complex.Bind import com.lambda.context.SafeContext import com.lambda.event.events.KeyboardEvent import com.lambda.event.events.MouseEvent -import com.lambda.event.events.PlayerEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack @@ -44,8 +43,6 @@ import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.Items import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket -import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket -import net.minecraft.screen.slot.SlotActionType import net.minecraft.util.Hand import net.minecraft.util.hit.HitResult @@ -236,7 +233,7 @@ object BetterFirework : Module( stack.bestItemMatch(player.hotbarAndStorage) ?.let { val swapSlotId = player.hotbarAndStorage.indexOf(it) - val hotbarSlotToSwapWith = player.hotbar.find { slot -> slot.isEmpty } ?.let { slot -> player.hotbar.indexOf(slot) } ?: 8 + val hotbarSlotToSwapWith = player.hotbar.find { slot -> slot.isEmpty }?.let { slot -> player.hotbar.indexOf(slot) } ?: 8 inventoryRequest { swap(swapSlotId, hotbarSlotToSwapWith) From e0acb2f48c57856c09b9f15c3e94e2252b5bc1fc Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Sun, 23 Nov 2025 18:11:37 +0000 Subject: [PATCH 14/16] whens and requests --- .../module/modules/movement/BetterFirework.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index cbb0ae418..21a0ace14 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -27,7 +27,6 @@ import com.lambda.event.events.MouseEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.material.StackSelection.Companion.selectStack -import com.lambda.interaction.request.hotbar.HotbarManager import com.lambda.interaction.request.hotbar.HotbarRequest import com.lambda.interaction.request.inventory.InventoryRequest.Companion.inventoryRequest import com.lambda.module.Module @@ -163,10 +162,10 @@ object BetterFirework : Module( fun onInteract() = runSafe { when { - !fireworkInteract -> false - player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET -> false - player.isGliding -> false // No need to do special magic if we are already holding fireworks and flying - mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel -> false + !fireworkInteract || + player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET || + player.isGliding || // No need to do special magic if we are already holding fireworks and flying + (mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel) -> false else -> { mc.itemUseCooldown += 4 val cancelInteract = player.canTakeoff || fireworkInteractCancel @@ -187,8 +186,8 @@ object BetterFirework : Module( fun onPick() = runSafe { when { - mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel -> false - !activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code -> false + (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) || + (!activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code) || takeoffState != TakeoffState.None -> false // Prevent using multiple times else -> { if (player.canOpenElytra || player.isGliding) { @@ -219,7 +218,7 @@ object BetterFirework : Module( stack.bestItemMatch(player.hotbar) ?.let { - val request = HotbarManager.request(HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0)) + val request = HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0) .submit(queueIfClosed = false) if (request.done) { interaction.interactItem(player, Hand.MAIN_HAND) @@ -238,7 +237,7 @@ object BetterFirework : Module( inventoryRequest { swap(swapSlotId, hotbarSlotToSwapWith) action { - val request = HotbarManager.request(HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)) + val request = HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true) .submit(queueIfClosed = false) if (request.done) { interaction.interactItem(player, Hand.MAIN_HAND) From 05a7d1ab98091087d1f330b49cb4f5c9bc7e3352 Mon Sep 17 00:00:00 2001 From: beanbag44 Date: Mon, 24 Nov 2025 00:29:14 +0000 Subject: [PATCH 15/16] forgot to update indenting --- .../com/lambda/module/modules/movement/BetterFirework.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 21a0ace14..164ae8907 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -187,8 +187,8 @@ object BetterFirework : Module( runSafe { when { (mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) || - (!activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code) || - takeoffState != TakeoffState.None -> false // Prevent using multiple times + (!activateButton.isMouseBind || activateButton.mouse != mc.options.pickItemKey.boundKey.code) || + takeoffState != TakeoffState.None -> false // Prevent using multiple times else -> { if (player.canOpenElytra || player.isGliding) { // If already gliding use another firework From f59490b139fd2266e545278873f76bdbf081bc9b Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Fri, 28 Nov 2025 00:15:20 +0100 Subject: [PATCH 16/16] Rename silent to Inventory Set default options that actually work --- .../lambda/module/modules/movement/BetterFirework.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt index 164ae8907..797be0e2d 100644 --- a/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt +++ b/src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt @@ -57,14 +57,14 @@ object BetterFirework : Module( private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract } private var clientSwing by setting("Swing", true, "Swing hand client side").group(Group.General) - private var silentUse by setting("Silent", true, "Silent use fireworks from the inventory") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) + private var invUse by setting("Inventory", true, "Use fireworks from inventory") { activateButton.key != KeyCode.Unbound.code }.group(Group.General) - override val hotbarConfig = HotbarSettings(this, Group.Hotbar).apply { - ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } + override val hotbarConfig = HotbarSettings(this, Group.Hotbar, vis = { false }).apply { + ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)); defaultValue(mutableSetOf(TickEvent.Pre)) } } - override val inventoryConfig = InventorySettings(this, Group.Inventory).apply { - ::tickStageMask.edit { immutableSet(setOf(TickEvent.Pre)) } + override val inventoryConfig = InventorySettings(this, Group.Inventory, vis = { false }).apply { + ::tickStageMask.edit { immutableSet(setOf(TickEvent.Pre)); defaultValue(mutableSetOf(TickEvent.Pre)) } } private enum class Group(override val displayName: String) : NamedEnum { @@ -96,7 +96,7 @@ object BetterFirework : Module( player.startGliding() connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) } - startFirework(silentUse) + startFirework(invUse) takeoffState = TakeoffState.None } }