Skip to content

Commit c84570f

Browse files
authored
FIX: Prevents betterfirework from trying to start flying without an elytra or a firework. Shows a warning message to the user instead. (#227)
Previously BetterFirework tried to fly without an Elytra. This fixes the issue.
1 parent 530b98b commit c84570f

File tree

1 file changed

+160
-141
lines changed

1 file changed

+160
-141
lines changed

src/main/kotlin/com/lambda/module/modules/movement/BetterFirework.kt

Lines changed: 160 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ import com.lambda.interaction.material.StackSelection.Companion.selectStack
3030
import com.lambda.module.Module
3131
import com.lambda.module.tag.ModuleTag
3232
import com.lambda.threading.runSafe
33+
import com.lambda.util.Communication.warn
3334
import com.lambda.util.KeyCode
3435
import com.lambda.util.Mouse
3536
import com.lambda.util.player.SlotUtils.hotbarAndInventoryStacks
3637
import com.lambda.util.player.SlotUtils.hotbarStacks
3738
import net.minecraft.client.network.ClientPlayerEntity
39+
import net.minecraft.entity.EquipmentSlot
3840
import net.minecraft.entity.effect.StatusEffects
3941
import net.minecraft.item.Items
4042
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket
@@ -43,35 +45,52 @@ import net.minecraft.util.Hand
4345
import net.minecraft.util.hit.HitResult
4446

4547
object BetterFirework : Module(
46-
name = "BetterFirework",
47-
description = "Automatic takeoff with fireworks",
48-
tag = ModuleTag.MOVEMENT,
48+
name = "BetterFirework",
49+
description = "Automatic takeoff with fireworks",
50+
tag = ModuleTag.MOVEMENT,
4951
) {
50-
private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework")
51-
.onPress {
52-
if (takeoffState != TakeoffState.None) return@onPress // Prevent using multiple times
53-
// If already gliding use another firework
54-
if (player.canOpenElytra || player.isGliding) takeoffState = TakeoffState.StartFlying
55-
else if (player.canTakeoff) takeoffState = TakeoffState.Jumping
56-
}
57-
private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind.EMPTY, "Firework use key for mid flight activation")
58-
.onPress { if (player.isGliding) takeoffState = TakeoffState.StartFlying }
59-
private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code }
60-
private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks")
61-
private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract }
62-
63-
private var clientSwing by setting("Swing", true, "Swing hand client side")
64-
private var invUse by setting("Inventory", true, "Use fireworks from inventory") { activateButton.key != KeyCode.Unbound.code }
65-
66-
private var takeoffState = TakeoffState.None
67-
68-
val ClientPlayerEntity.canTakeoff: Boolean
69-
get() = isOnGround || canOpenElytra
70-
71-
val ClientPlayerEntity.canOpenElytra: Boolean
72-
get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION)
73-
74-
init {
52+
private var activateButton by setting("Activate Key", Bind(0, 0, Mouse.Middle.ordinal), "Button to activate Firework")
53+
.onPress {
54+
if (!player.isElytraEquipped) {
55+
warn("You need to equip an elytra to use this module!")
56+
return@onPress
57+
}
58+
if (!player.hasFireworks) {
59+
warn("You need to have fireworks in your inventory to use this module!")
60+
return@onPress
61+
}
62+
// Prevent using multiple times
63+
if (takeoffState != TakeoffState.None) return@onPress
64+
// If already gliding use another firework
65+
if (player.canOpenElytra || player.isGliding) takeoffState = TakeoffState.StartFlying
66+
else if (player.canTakeoff) takeoffState = TakeoffState.Jumping
67+
}
68+
private var midFlightActivationKey by setting("Mid-Flight Activation Key", Bind.EMPTY, "Firework use key for mid flight activation")
69+
.onPress { if (player.isGliding) takeoffState = TakeoffState.StartFlying }
70+
private var middleClickCancel by setting("Middle Click Cancel", false, description = "Cancel pick block action on middle mouse click") { activateButton.key != KeyCode.Unbound.code }
71+
private var fireworkInteract by setting("Right Click Fly", true, "Automatically start flying when right clicking fireworks")
72+
private var fireworkInteractCancel by setting("Right Click Cancel", false, "Cancel block interactions while holding fireworks") { fireworkInteract }
73+
74+
private var clientSwing by setting("Swing", true, "Swing hand client side")
75+
private var invUse by setting("Inventory", true, "Use fireworks from inventory") { activateButton.key != KeyCode.Unbound.code }
76+
77+
private var takeoffState = TakeoffState.None
78+
79+
val ClientPlayerEntity.isElytraEquipped: Boolean
80+
get() = inventory.equipment.get(EquipmentSlot.CHEST)?.item == Items.ELYTRA
81+
82+
val ClientPlayerEntity.hasFireworks: Boolean
83+
get() = selectStack { isItem(Items.FIREWORK_ROCKET) }
84+
.filterStacks(inventory.mainStacks)
85+
.isNotEmpty() || offHandStack.item == Items.FIREWORK_ROCKET
86+
87+
val ClientPlayerEntity.canTakeoff: Boolean
88+
get() = (isOnGround || canOpenElytra) && isElytraEquipped && hasFireworks
89+
90+
val ClientPlayerEntity.canOpenElytra: Boolean
91+
get() = !abilities.flying && !isClimbing && !isGliding && !isTouchingWater && !isOnGround && !hasVehicle() && !hasStatusEffect(StatusEffects.LEVITATION)
92+
93+
init {
7594
setDefaultAutomationConfig {
7695
applyEdits {
7796
hideAllGroupsExcept(hotbarConfig, inventoryConfig)
@@ -80,117 +99,117 @@ object BetterFirework : Module(
8099
}
81100
}
82101

83-
listen<TickEvent.Pre> {
84-
when (takeoffState) {
85-
TakeoffState.None -> {}
86-
87-
TakeoffState.Jumping -> {
88-
player.jump()
89-
takeoffState = TakeoffState.StartFlying
90-
}
91-
92-
TakeoffState.StartFlying -> {
93-
if (player.canOpenElytra) {
94-
player.startGliding()
95-
connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING))
96-
}
97-
startFirework(invUse)
98-
takeoffState = TakeoffState.None
99-
}
100-
}
101-
}
102-
}
103-
104-
/**
105-
* Returns true if the mc item interaction should be canceled
106-
*/
107-
@JvmStatic
108-
fun onInteract() =
109-
runSafe {
110-
when {
111-
!fireworkInteract ||
112-
player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET ||
113-
player.isGliding || // No need to do special magic if we are already holding fireworks and flying
114-
(mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel) -> false
115-
else -> {
116-
mc.itemUseCooldown += 4
117-
val cancelInteract = player.canTakeoff || fireworkInteractCancel
118-
if (player.canTakeoff) {
119-
takeoffState = TakeoffState.Jumping
120-
} else if (player.canOpenElytra) {
121-
takeoffState = TakeoffState.StartFlying
122-
}
123-
cancelInteract
124-
}
125-
}
126-
} ?: false
127-
128-
/**
129-
* Returns true when the pick interaction should be canceled.
130-
*/
131-
@JvmStatic
132-
fun onPick() =
133-
runSafe {
134-
when {
135-
(mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) ||
136-
activateButton.mouse != mc.options.pickItemKey.boundKey.code ||
137-
takeoffState != TakeoffState.None -> false // Prevent using multiple times
138-
else -> middleClickCancel
139-
}
140-
} ?: false
141-
142-
fun SafeContext.sendSwing() {
143-
if (clientSwing) {
144-
player.swingHand(Hand.MAIN_HAND)
145-
} else {
146-
connection.sendPacket(HandSwingC2SPacket(Hand.MAIN_HAND))
147-
}
148-
}
149-
150-
/**
151-
* Use a firework from the hotbar or inventory if possible.
152-
* Return true if a firework has been used
153-
*/
154-
@JvmStatic
155-
fun SafeContext.startFirework(silent: Boolean) {
156-
val stack = selectStack(count = 1) { isItem(Items.FIREWORK_ROCKET) }
157-
158-
stack.bestItemMatch(player.hotbarStacks)
159-
?.let {
160-
val request = HotbarRequest(player.hotbarStacks.indexOf(it), this@BetterFirework, keepTicks = 0)
161-
.submit(queueIfMismatchedStage = false)
162-
if (request.done) {
163-
interaction.interactItem(player, Hand.MAIN_HAND)
164-
sendSwing()
165-
}
166-
return
167-
}
168-
169-
if (!silent) return
170-
171-
stack.bestItemMatch(player.hotbarAndInventoryStacks)
172-
?.let {
173-
val swapSlotId = player.hotbarAndInventoryStacks.indexOf(it)
174-
val hotbarSlotToSwapWith = player.hotbarStacks.find { slot -> slot.isEmpty }?.let { slot -> player.hotbarStacks.indexOf(slot) } ?: 8
175-
176-
inventoryRequest {
177-
swap(swapSlotId, hotbarSlotToSwapWith)
178-
action {
179-
val request = HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)
180-
.submit(queueIfMismatchedStage = false)
181-
if (request.done) {
182-
interaction.interactItem(player, Hand.MAIN_HAND)
183-
sendSwing()
184-
}
185-
}
186-
swap(swapSlotId, hotbarSlotToSwapWith)
187-
}.submit()
188-
}
189-
}
190-
191-
enum class TakeoffState {
192-
None,
193-
Jumping,
194-
StartFlying
195-
}
102+
listen<TickEvent.Pre> {
103+
when (takeoffState) {
104+
TakeoffState.None -> {}
105+
106+
TakeoffState.Jumping -> {
107+
player.jump()
108+
takeoffState = TakeoffState.StartFlying
109+
}
110+
111+
TakeoffState.StartFlying -> {
112+
if (player.canOpenElytra) {
113+
player.startGliding()
114+
connection.sendPacket(ClientCommandC2SPacket(player, ClientCommandC2SPacket.Mode.START_FALL_FLYING))
115+
}
116+
startFirework(invUse)
117+
takeoffState = TakeoffState.None
118+
}
119+
}
120+
}
121+
}
122+
123+
/**
124+
* Returns true if the mc item interaction should be canceled
125+
*/
126+
@JvmStatic
127+
fun onInteract() =
128+
runSafe {
129+
when {
130+
!fireworkInteract ||
131+
player.inventory.selectedStack?.item != Items.FIREWORK_ROCKET ||
132+
player.isGliding || // No need to do special magic if we are already holding fireworks and flying
133+
(mc.crosshairTarget != null && mc.crosshairTarget!!.type != HitResult.Type.MISS && !fireworkInteractCancel) -> false
134+
else -> {
135+
mc.itemUseCooldown += 4
136+
val cancelInteract = player.canTakeoff || fireworkInteractCancel
137+
if (player.canTakeoff) {
138+
takeoffState = TakeoffState.Jumping
139+
} else if (player.canOpenElytra) {
140+
takeoffState = TakeoffState.StartFlying
141+
}
142+
cancelInteract
143+
}
144+
}
145+
} ?: false
146+
147+
/**
148+
* Returns true when the pick interaction should be canceled.
149+
*/
150+
@JvmStatic
151+
fun onPick() =
152+
runSafe {
153+
when {
154+
(mc.crosshairTarget?.type == HitResult.Type.BLOCK && !middleClickCancel) ||
155+
activateButton.mouse != mc.options.pickItemKey.boundKey.code ||
156+
takeoffState != TakeoffState.None -> false // Prevent using multiple times
157+
else -> middleClickCancel
158+
}
159+
} ?: false
160+
161+
fun SafeContext.sendSwing() {
162+
if (clientSwing) {
163+
player.swingHand(Hand.MAIN_HAND)
164+
} else {
165+
connection.sendPacket(HandSwingC2SPacket(Hand.MAIN_HAND))
166+
}
167+
}
168+
169+
/**
170+
* Use a firework from the hotbar or inventory if possible.
171+
* Return true if a firework has been used
172+
*/
173+
@JvmStatic
174+
fun SafeContext.startFirework(silent: Boolean) {
175+
val stack = selectStack(count = 1) { isItem(Items.FIREWORK_ROCKET) }
176+
177+
stack.bestItemMatch(player.hotbarStacks)
178+
?.let {
179+
val request = HotbarRequest(player.hotbarStacks.indexOf(it), this@BetterFirework, keepTicks = 0)
180+
.submit(queueIfMismatchedStage = false)
181+
if (request.done) {
182+
interaction.interactItem(player, Hand.MAIN_HAND)
183+
sendSwing()
184+
}
185+
return
186+
}
187+
188+
if (!silent) return
189+
190+
stack.bestItemMatch(player.hotbarAndInventoryStacks)
191+
?.let {
192+
val swapSlotId = player.hotbarAndInventoryStacks.indexOf(it)
193+
val hotbarSlotToSwapWith = player.hotbarStacks.find { slot -> slot.isEmpty }?.let { slot -> player.hotbarStacks.indexOf(slot) } ?: 8
194+
195+
inventoryRequest {
196+
swap(swapSlotId, hotbarSlotToSwapWith)
197+
action {
198+
val request = HotbarRequest(hotbarSlotToSwapWith, this@BetterFirework, keepTicks = 0, nowOrNothing = true)
199+
.submit(queueIfMismatchedStage = false)
200+
if (request.done) {
201+
interaction.interactItem(player, Hand.MAIN_HAND)
202+
sendSwing()
203+
}
204+
}
205+
swap(swapSlotId, hotbarSlotToSwapWith)
206+
}.submit()
207+
}
208+
}
209+
210+
enum class TakeoffState {
211+
None,
212+
Jumping,
213+
StartFlying
214+
}
196215
}

0 commit comments

Comments
 (0)