-
Notifications
You must be signed in to change notification settings - Fork 18
Feature (Module): Add BetterFirework Module #154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
9fe2924
Add BetterFirework Module
IceTank 9f8f08d
Refactor BetterFirework settings and some code
IceTank 2e9dda1
Update logic handling in BetterFirework.kt
IceTank 10f1127
Nits
emyfops b30d8b8
Use HotbarManager to swap to firework slots
IceTank 903aff1
Change enums to Camel case
IceTank 99a3940
Add Universal Keybind to BetterFirework.kt
IceTank 6aea738
Simplify Keyboard and Mouse Event listener
IceTank b9b22fb
Merge remote-tracking branch 'origin/1.21.5' into feature/module/Bett…
IceTank 052fdff
Update BetterFirework to use InventoryManager for inventory switching…
IceTank 7996ec9
Clean up code
IceTank 060a7d9
Add mid-flight activation keybind
IceTank d9bd005
Update BetterFirework code
IceTank 0d513e1
Lint code
IceTank e0acb2f
whens and requests
beanbag44 05a7d1a
forgot to update indenting
beanbag44 f59490b
Rename silent to Inventory
IceTank e6d7e3c
Merge branch '1.21.5' into feature/module/BetterFirework
emyfops File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
257 changes: 257 additions & 0 deletions
257
src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| /* | ||
| * 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 <http://www.gnu.org/licenses/>. | ||
| */ | ||
|
|
||
| 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 | ||
| 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 | ||
| 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 | ||
| 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.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.util.Hand | ||
| import net.minecraft.util.hit.HitResult | ||
|
|
||
| object BetterFirework : Module( | ||
| name = "BetterFirework", | ||
| description = "Automatic takeoff with fireworks", | ||
| 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 } | ||
|
|
||
| private var clientSwing by setting("Swing", true, "Swing hand client side").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, vis = { false }).apply { | ||
| ::sequenceStageMask.edit { immutableSet(setOf(TickEvent.Pre)); defaultValue(mutableSetOf(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 { | ||
| General("General"), | ||
| Hotbar("Hotbar"), | ||
| Inventory("Inventory") | ||
| } | ||
|
|
||
| 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<TickEvent.Pre> { | ||
| when (takeoffState) { | ||
| TakeoffState.None -> {} | ||
|
|
||
| TakeoffState.Jumping -> { | ||
| player.jump() | ||
| takeoffState = TakeoffState.StartFlying | ||
| } | ||
|
|
||
| TakeoffState.StartFlying -> { | ||
| if (player.canOpenElytra) { | ||
| player.startGliding() | ||
| connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING)) | ||
| } | ||
| startFirework(invUse) | ||
| takeoffState = TakeoffState.None | ||
| } | ||
| } | ||
| } | ||
| listen<MouseEvent.Click> { | ||
| if (!it.isPressed) { | ||
| return@listen | ||
| } | ||
| if (it.satisfies(activateButton)) { | ||
| if (activateButton.mouse == mc.options.pickItemKey.boundKey.code) { | ||
| return@listen | ||
| } | ||
| 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 | ||
| } | ||
| } | ||
| } | ||
| if (it.satisfies(midFlightActivationKey)) { | ||
| runSafe { | ||
| if (player.isGliding) | ||
| takeoffState = TakeoffState.StartFlying | ||
| } | ||
| } | ||
| } | ||
| listen<KeyboardEvent.Press> { | ||
| 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 (player.isGliding) | ||
| takeoffState = TakeoffState.StartFlying | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns true if the mc item interaction should be canceled | ||
| */ | ||
| @JvmStatic | ||
| fun onInteract() = | ||
| runSafe { | ||
| when { | ||
| !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 | ||
| if (player.canTakeoff) { | ||
| takeoffState = TakeoffState.Jumping | ||
| } else if (player.canOpenElytra) { | ||
| takeoffState = TakeoffState.StartFlying | ||
| } | ||
| cancelInteract | ||
| } | ||
| } | ||
| } ?: false | ||
|
|
||
| /** | ||
| * Returns true when the pick interaction should be canceled. | ||
| */ | ||
| @JvmStatic | ||
| fun onPick() = | ||
| 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 | ||
| else -> { | ||
| if (player.canOpenElytra || player.isGliding) { | ||
| // If already gliding use another firework | ||
| takeoffState = TakeoffState.StartFlying | ||
| } else if (player.canTakeoff) { | ||
| takeoffState = TakeoffState.Jumping | ||
| } | ||
| middleClickCancel | ||
| } | ||
| } | ||
| } ?: false | ||
|
|
||
| fun SafeContext.sendSwing() { | ||
| 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) { | ||
| val stack = selectStack(count = 1) { isItem(Items.FIREWORK_ROCKET) } | ||
|
|
||
| stack.bestItemMatch(player.hotbar) | ||
| ?.let { | ||
| val request = HotbarRequest(player.hotbar.indexOf(it), this@BetterFirework, keepTicks = 0) | ||
| .submit(queueIfClosed = false) | ||
| if (request.done) { | ||
| interaction.interactItem(player, Hand.MAIN_HAND) | ||
| sendSwing() | ||
| } | ||
| return | ||
| } | ||
|
|
||
| if (!silent) return | ||
|
|
||
| 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 | ||
|
|
||
| inventoryRequest { | ||
| swap(swapSlotId, hotbarSlotToSwapWith) | ||
| action { | ||
| val 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() | ||
| } | ||
| } | ||
|
|
||
| enum class TakeoffState { | ||
| None, | ||
| Jumping, | ||
| StartFlying | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.