1+ /*
2+ * Copyright 2025 Lambda
3+ *
4+ * This program is free software: you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation, either version 3 of the License, or
7+ * (at your option) any later version.
8+ *
9+ * This program is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ * GNU General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU General Public License
15+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16+ */
17+
18+ package com.lambda.task.tasks
19+
20+ import baritone.api.pathing.goals.GoalBlock
21+ import com.lambda.config.groups.InteractionConfig
22+ import com.lambda.config.groups.RotationConfig
23+ import com.lambda.context.SafeContext
24+ import com.lambda.event.events.TickEvent
25+ import com.lambda.event.events.WorldEvent
26+ import com.lambda.event.listener.SafeListener.Companion.listen
27+ import com.lambda.interaction.RotationManager.rotate
28+ import com.lambda.interaction.construction.context.BreakContext
29+ import com.lambda.interaction.visibilty.VisibilityChecker.lookAtBlock
30+ import com.lambda.module.modules.client.TaskFlowModule
31+ import com.lambda.task.Task
32+ import com.lambda.util.BaritoneUtils
33+ import com.lambda.util.BlockUtils.blockState
34+ import com.lambda.util.extension.inventorySlots
35+ import com.lambda.util.item.ItemUtils.block
36+ import com.lambda.util.player.SlotUtils.clickSlot
37+ import com.lambda.util.player.SlotUtils.hotbarAndStorage
38+ import net.minecraft.block.BlockState
39+ import net.minecraft.entity.ItemEntity
40+ import net.minecraft.screen.slot.SlotActionType
41+ import net.minecraft.util.math.BlockPos
42+ import net.minecraft.util.math.Direction
43+
44+ class PacketBreakBlock @Ta5kBuilder constructor(
45+ private val ctx : BreakContext ,
46+ private val collectDrop : Boolean = false ,
47+ private val rotation : RotationConfig = TaskFlowModule .rotation,
48+ private val interact : InteractionConfig = TaskFlowModule .interact,
49+ private val sides : Set <Direction > = Direction .entries.toSet(),
50+ private val rotate : Boolean = TaskFlowModule .build.rotateForBreak,
51+ private val swingHand : Boolean = TaskFlowModule .interact.swingHand,
52+ ) : Task<ItemEntity?>() {
53+ override val name get() = " Packet breaking ${ctx.result.blockPos.toShortString()} "
54+
55+ val blockPos: BlockPos get() = ctx.result.blockPos
56+
57+ private var beginState: BlockState ? = null
58+ val SafeContext .blockState: BlockState
59+ get() = blockPos.blockState(world)
60+
61+ private var drop: ItemEntity ? = null
62+ private var state = State .BREAKING
63+ private var isValid = false
64+
65+ enum class State {
66+ BREAKING , COLLECTING
67+ }
68+
69+ override fun SafeContext.onStart () {
70+ if (done()) {
71+ success(null )
72+ return
73+ }
74+
75+ beginState = blockState
76+
77+ if (! rotate || ctx.instantBreak) {
78+ hitBlock(ctx.result.side)
79+ }
80+ }
81+
82+ init {
83+ rotate {
84+ onUpdate {
85+ if (state != State .BREAKING ) return @onUpdate null
86+ if (! rotate || ctx.instantBreak) return @onUpdate null
87+
88+ lookAtBlock(blockPos, rotation, interact, sides)
89+ }
90+ onReceive { context ->
91+ isValid = context.isValid
92+ }
93+ }
94+
95+ listen<TickEvent .Pre > {
96+ drop?.let { itemDrop ->
97+ if (! world.entities.contains(itemDrop)) {
98+ BaritoneUtils .cancel()
99+ success(itemDrop)
100+ return @listen
101+ }
102+
103+ if (player.hotbarAndStorage.none { it.isEmpty }) {
104+ player.currentScreenHandler.inventorySlots.firstOrNull {
105+ it.stack.item.block in TaskFlowModule .inventory.disposables
106+ }?.let {
107+ clickSlot(it.id, 1 , SlotActionType .THROW )
108+ }
109+ return @listen
110+ }
111+
112+ BaritoneUtils .setGoalAndPath(GoalBlock (itemDrop.blockPos))
113+ return @listen
114+ } ? : BaritoneUtils .cancel()
115+
116+ if (isValid || ! rotate || ctx.instantBreak) {
117+ hitBlock(ctx.result.side)
118+ }
119+
120+ if (done()) {
121+ if (! collectDrop) {
122+ BaritoneUtils .cancel()
123+ success(null )
124+ }
125+ }
126+ }
127+
128+ // ToDo: Find out when the stack entity is filled with the item
129+ listen<WorldEvent .EntityUpdate > {
130+ if (collectDrop
131+ && it.entity is ItemEntity
132+ && it.entity.pos.isInRange(blockPos.toCenterPos(), 0.5 )
133+ ) {
134+ drop = it.entity
135+ state = State .COLLECTING
136+ }
137+ }
138+ }
139+
140+ private fun SafeContext.done () = blockState.isAir && ! collectDrop
141+
142+ private fun SafeContext.hitBlock (side : Direction ) {
143+ if (interaction.updateBlockBreakingProgress(blockPos, side)) {
144+ if (player.isCreative) interaction.blockBreakingCooldown = 0
145+ if (swingHand) player.swingHand(ctx.hand)
146+ }
147+ }
148+ }
0 commit comments