@@ -26,32 +26,44 @@ import com.lambda.event.events.WorldEvent
2626import com.lambda.event.listener.SafeListener.Companion.listen
2727import com.lambda.interaction.RotationManager.rotate
2828import com.lambda.interaction.construction.context.BreakContext
29+ import com.lambda.interaction.material.StackSelection.Companion.select
2930import com.lambda.interaction.visibilty.VisibilityChecker.lookAtBlock
3031import com.lambda.module.modules.client.TaskFlowModule
3132import com.lambda.task.Task
3233import com.lambda.util.BaritoneUtils
3334import com.lambda.util.BlockUtils.blockState
35+ import com.lambda.util.BlockUtils.calcItemBlockBreakingDelta
3436import com.lambda.util.extension.inventorySlots
37+ import com.lambda.util.item.ItemStackUtils.equal
3538import com.lambda.util.item.ItemUtils.block
3639import com.lambda.util.player.SlotUtils.clickSlot
3740import com.lambda.util.player.SlotUtils.hotbarAndStorage
3841import net.minecraft.block.BlockState
42+ import net.minecraft.client.sound.PositionedSoundInstance
43+ import net.minecraft.client.sound.SoundInstance
3944import net.minecraft.entity.ItemEntity
45+ import net.minecraft.item.Item
46+ import net.minecraft.item.ItemStack
4047import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket
4148import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action
4249import net.minecraft.screen.slot.SlotActionType
50+ import net.minecraft.sound.SoundCategory
4351import net.minecraft.util.math.BlockPos
4452import net.minecraft.util.math.Direction
4553
4654class PacketBreakBlock @Ta5kBuilder constructor(
4755 private val ctx : BreakContext ,
56+ private var tool : Item ? ,
57+ private val validateBreak : Boolean = true ,
58+ private val swingHand : SwingHandStyle = SwingHandStyle .Start ,
59+ private val breakingTexture : Boolean = true ,
60+ private val breakingSound : Boolean = true ,
61+ private val breakingParticles : Boolean = true ,
4862 private val collectDrop : Boolean = false ,
4963 private val rotation : RotationConfig = TaskFlowModule .rotation,
5064 private val interact : InteractionConfig = TaskFlowModule .interact,
51- private val validateBreak : Boolean = true ,
5265 private val sides : Set <Direction > = Direction .entries.toSet(),
5366 private val rotate : Boolean = TaskFlowModule .build.rotateForBreak,
54- private val swingHand : SwingHandStyle = SwingHandStyle .Start ,
5567) : Task<ItemEntity?>() {
5668 override val name get() = " Packet breaking ${ctx.result.blockPos.toShortString()} "
5769
@@ -65,7 +77,11 @@ class PacketBreakBlock @Ta5kBuilder constructor(
6577 private var state = State .BREAKING
6678 private var isValid = false
6779
68- private var breakAmount = 0f
80+ private var previousToolStack: ItemStack ? = null
81+ private var toolStack: ItemStack ? = null
82+ private var toolSlot: Int = - 1
83+
84+ private var pendingConfirmation = false
6985
7086 enum class State {
7187 BREAKING , COLLECTING
@@ -80,8 +96,9 @@ class PacketBreakBlock @Ta5kBuilder constructor(
8096 beginState = blockState
8197
8298 if (! rotate || ctx.instantBreak) {
99+ updateToolInformation()
83100 stepDamage(ctx.result.side)
84- if (swingHand != SwingHandStyle .End ) player. swingHand(ctx.hand )
101+ if (swingHand != SwingHandStyle .End && swingHand.notNone()) swing( )
85102 }
86103 }
87104
@@ -120,7 +137,27 @@ class PacketBreakBlock @Ta5kBuilder constructor(
120137 } ? : BaritoneUtils .cancel()
121138
122139 if (isValid || ! rotate || ctx.instantBreak) {
140+ updateToolInformation()
141+ if (! toolStack.equal(previousToolStack)) {
142+ val currentBlockState = blockState
143+ val currentBreakDelta = currentBlockState.calcItemBlockBreakingDelta(
144+ player, world, ctx.expectedPos, toolStack!!
145+ )
146+ val previousBreakDelta = currentBlockState.calcItemBlockBreakingDelta(
147+ player, world, ctx.expectedPos, toolStack!!
148+ )
149+ val multiplier = previousBreakDelta / currentBreakDelta
150+ interaction.currentBreakingProgress * = multiplier
151+ }
123152 stepDamage(ctx.result.side)
153+ if ((
154+ swingHand != SwingHandStyle .Start && swingHand.notNone()
155+ && interaction.blockBreakingProgress >= 1.0f
156+ )
157+ || swingHand == SwingHandStyle .Constant
158+ ) {
159+ swing()
160+ }
124161 }
125162
126163 if (done()) {
@@ -145,14 +182,145 @@ class PacketBreakBlock @Ta5kBuilder constructor(
145182 }
146183
147184 private fun SafeContext.done () =
148- ! collectDrop && (blockState.isAir || (! validateBreak && breakAmount >= 1.0f ))
185+ ! collectDrop && blockState.isAir
186+
187+ private fun SafeContext.stepDamage (side : Direction ) =
188+ updateBlockBreakingProgress(blockPos, side)
189+
190+ /* *
191+ * modified version of the vanilla method to change some behaviours like removing the block breaking cooldown
192+ * and allow for validating the break by waiting for the server to respond
193+ */
194+ private fun SafeContext.updateBlockBreakingProgress (pos : BlockPos , side : Direction ): Boolean {
195+ if (interaction.currentGameMode.isCreative && world.worldBorder.contains(pos)) {
196+ interaction.sendSequencedPacket(world) { sequence: Int ->
197+ interaction.breakBlock(pos)
198+ PlayerActionC2SPacket (Action .START_DESTROY_BLOCK , pos, side, sequence)
199+ }
200+ return true
201+ }
202+
203+ if (! interaction.isCurrentlyBreaking(pos)) return attackBlock(pos, side)
204+
205+ val blockState: BlockState = world.getBlockState(pos)
206+ if (blockState.isAir) {
207+ interaction.breakingBlock = false
208+ return false
209+ }
210+
211+ interaction.currentBreakingProgress + = blockState.calcItemBlockBreakingDelta(
212+ player,
213+ world,
214+ pos,
215+ toolStack!!
216+ )
217+
218+ if (breakingSound && interaction.blockBreakingSoundCooldown % 4.0f == 0.0f ) {
219+ val blockSoundGroup = blockState.soundGroup
220+ mc
221+ .soundManager
222+ .play(
223+ PositionedSoundInstance (
224+ blockSoundGroup.hitSound,
225+ SoundCategory .BLOCKS ,
226+ (blockSoundGroup.getVolume() + 1.0f ) / 8.0f ,
227+ blockSoundGroup.getPitch() * 0.5f ,
228+ SoundInstance .createRandom(),
229+ pos
230+ )
231+ )
232+ }
233+
234+ interaction.blockBreakingSoundCooldown++
235+ if (interaction.currentBreakingProgress >= 1.0f ) {
236+ interaction.breakingBlock = false
237+ interaction.sendSequencedPacket(world) { sequence: Int ->
238+ interaction.breakBlock(pos)
239+ PlayerActionC2SPacket (Action .STOP_DESTROY_BLOCK , pos, side, sequence)
240+ }
241+ interaction.blockBreakingSoundCooldown = 0.0f
242+ }
149243
150- private fun SafeContext.stepDamage (side : Direction ) {
151- if (interaction.updateBlockBreakingProgress(blockPos, side)) {
152- if (player.isCreative) interaction.blockBreakingCooldown = 0
244+ if (breakingTexture) {
245+ world.setBlockBreakingInfo(
246+ player.id,
247+ interaction.currentBreakingPos,
248+ interaction.blockBreakingProgress
249+ )
153250 }
251+
252+ return true
154253 }
155254
255+ /* *
256+ * modified version of the vanilla method
257+ */
258+ private fun SafeContext.attackBlock (pos : BlockPos , side : Direction ): Boolean {
259+ if (player.isBlockBreakingRestricted(world, pos, interaction.currentGameMode)) return false
260+ if (! world.worldBorder.contains(pos)) return false
261+
262+ if (interaction.currentGameMode.isCreative) {
263+ interaction.sendSequencedPacket(world) { sequence: Int ->
264+ interaction.breakBlock(pos)
265+ PlayerActionC2SPacket (Action .START_DESTROY_BLOCK , pos, side, sequence)
266+ }
267+ } else if (! interaction.breakingBlock || ! interaction.isCurrentlyBreaking(pos)) {
268+ if (interaction.breakingBlock) {
269+ connection.sendPacket(
270+ PlayerActionC2SPacket (
271+ Action .ABORT_DESTROY_BLOCK ,
272+ interaction.currentBreakingPos, side
273+ )
274+ )
275+ }
276+
277+ val blockState: BlockState = world.getBlockState(pos)
278+ interaction.sendSequencedPacket(world) { sequence: Int ->
279+ val notAir = ! blockState.isAir
280+ if (notAir && interaction.currentBreakingProgress == 0.0f ) {
281+ blockState.onBlockBreakStart(world, pos, player)
282+ }
283+
284+ if (notAir && blockState.calcItemBlockBreakingDelta(player, world, pos, getToolItemStack()) >= 1.0f ) {
285+ interaction.breakBlock(pos)
286+ } else {
287+ interaction.apply {
288+ breakingBlock = true
289+ currentBreakingPos = pos
290+ selectedStack = toolStack
291+ currentBreakingProgress = 0.0f
292+ blockBreakingSoundCooldown = 0.0f
293+ if (breakingTexture) {
294+ world.setBlockBreakingInfo(
295+ player.id,
296+ currentBreakingPos,
297+ blockBreakingProgress
298+ )
299+ }
300+ }
301+ }
302+ PlayerActionC2SPacket (Action .START_DESTROY_BLOCK , pos, side, sequence)
303+ }
304+ }
305+
306+ return true
307+ }
308+
309+ private fun SafeContext.updateToolInformation () {
310+ previousToolStack = toolStack
311+ toolStack = tool?.select()?.itemStack ? : player.mainHandStack
312+ if (previousToolStack == null ) {
313+ previousToolStack = toolStack
314+ }
315+ toolSlot = player.inventory.getSlotWithStack(toolStack)
316+ }
317+
318+ private fun SafeContext.swing () =
319+ player.swingHand(player.activeHand)
320+
321+ private fun SafeContext.getToolItemStack (): ItemStack =
322+ tool?.select()?.itemStack ? : player.mainHandStack
323+
156324 private fun SafeContext.startBreakPacket (pos : BlockPos , direction : Direction ) =
157325 breakPacket(pos, direction, Action .START_DESTROY_BLOCK )
158326
@@ -175,6 +343,9 @@ class PacketBreakBlock @Ta5kBuilder constructor(
175343 Constant ,
176344 StartAndEnd ,
177345 Start ,
178- End
346+ End ,
347+ None ;
348+
349+ fun notNone () = this != None
179350 }
180351}
0 commit comments