1717
1818package com.lambda.interaction.request.breaking
1919
20- import com.lambda.Lambda.mc
2120import com.lambda.config.groups.TickStage
2221import com.lambda.context.SafeContext
2322import com.lambda.event.Event
@@ -37,26 +36,23 @@ import com.lambda.interaction.request.RequestHandler
3736import com.lambda.interaction.request.breaking.BreakConfig.BreakConfirmationMode
3837import com.lambda.interaction.request.breaking.BreakConfig.BreakMode
3938import com.lambda.interaction.request.breaking.BreakManager.activeRequest
40- import com.lambda.interaction.request.breaking.BreakManager.preEvent
4139import com.lambda.interaction.request.breaking.BreakManager.processRequest
4240import com.lambda.interaction.request.breaking.BreakType.Primary
41+ import com.lambda.interaction.request.breaking.BrokenBlockHandler.destroyBlock
42+ import com.lambda.interaction.request.breaking.BrokenBlockHandler.pendingBreaks
43+ import com.lambda.interaction.request.breaking.BrokenBlockHandler.setPendingConfigs
44+ import com.lambda.interaction.request.breaking.BrokenBlockHandler.startPending
4345import com.lambda.interaction.request.hotbar.HotbarManager
4446import com.lambda.interaction.request.placing.PlaceManager
4547import com.lambda.interaction.request.rotation.RotationRequest
46- import com.lambda.module.modules.client.TaskFlowModule
4748import com.lambda.threading.runSafe
4849import com.lambda.util.BlockUtils.blockState
4950import com.lambda.util.BlockUtils.calcItemBlockBreakingDelta
50- import com.lambda.util.BlockUtils.fluidState
51- import com.lambda.util.BlockUtils.matches
52- import com.lambda.util.Communication.info
5351import com.lambda.util.Communication.warn
54- import com.lambda.util.collections.LimitedDecayQueue
5552import com.lambda.util.item.ItemUtils.block
5653import com.lambda.util.player.gamemode
5754import com.lambda.util.player.swingHand
5855import net.minecraft.block.BlockState
59- import net.minecraft.block.OperatorBlock
6056import net.minecraft.client.sound.PositionedSoundInstance
6157import net.minecraft.client.sound.SoundInstance
6258import net.minecraft.entity.ItemEntity
@@ -65,12 +61,10 @@ import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action
6561import net.minecraft.sound.SoundCategory
6662import net.minecraft.util.Hand
6763import net.minecraft.util.math.BlockPos
68- import net.minecraft.util.math.ChunkSectionPos
6964
7065object BreakManager : RequestHandler<BreakRequest>(
7166 *TickStage .entries.toTypedArray(),
72- preOpen = { activeRequest?.let { processRequest(it) } },
73- onOpen = { preEvent() }
67+ onOpen = { activeRequest?.let { processRequest(it) } }
7468), PositionBlocking {
7569 private var primaryBreak: BreakInfo ?
7670 get() = breakInfos[0 ]
@@ -80,30 +74,12 @@ object BreakManager : RequestHandler<BreakRequest>(
8074 set(value) { breakInfos[1 ] = value }
8175 private val breakInfos = arrayOfNulls<BreakInfo >(2 )
8276
83- private val pendingBreaks = LimitedDecayQueue <BreakInfo >(
84- TaskFlowModule .build.maxPendingInteractions, TaskFlowModule .build.interactionTimeout * 50L
85- ) { info ->
86- mc.world?.let { world ->
87- val pos = info.context.expectedPos
88- val loaded = world.isChunkLoaded(ChunkSectionPos .getSectionCoord(pos.x), ChunkSectionPos .getSectionCoord(pos.z))
89- if (! loaded) return @let
90-
91- info(" ${info::class .simpleName} at ${info.context.expectedPos.toShortString()} timed out" )
92-
93- val awaitThenBreak = info.breakConfig.breakConfirmation != BreakConfirmationMode .AwaitThenBreak
94- if (! info.broken && awaitThenBreak) {
95- world.setBlockState(info.context.expectedPos, info.context.checkedState)
96- }
97- }
98- info.pendingInteractions.remove(info.context)
99- }
10077 private val pendingBreakCount get() = breakInfos.count { it != null } + pendingBreaks.size
101-
102- private var activeRequest: BreakRequest ? = null
103-
10478 override val blockedPositions
10579 get() = breakInfos.mapNotNull { it?.context?.expectedPos } + pendingBreaks.map { it.context.expectedPos }
10680
81+ private var activeRequest: BreakRequest ? = null
82+
10783 private var rotationRequest: RotationRequest ? = null
10884 private val rotated get() = rotationRequest?.done != false
10985
@@ -140,29 +116,6 @@ object BreakManager : RequestHandler<BreakRequest>(
140116 }
141117
142118 listen<WorldEvent .BlockUpdate .Server >(priority = Int .MIN_VALUE + 1 ) { event ->
143- pendingBreaks
144- .firstOrNull { it.context.expectedPos == event.pos }
145- ?.let { pending ->
146- // return if the state hasn't changed
147- if (event.newState.matches(pending.context.checkedState))
148- return @listen
149-
150- // return if the block's not broken
151- if (! matchesTargetState(event.pos, pending.context.targetState, event.newState)) {
152- pending.stopPending()
153- return @listen
154- }
155-
156- if (pending.breakConfig.breakConfirmation == BreakConfirmationMode .AwaitThenBreak ) {
157- destroyBlock(pending)
158- }
159- pending.internalOnBreak()
160- if (pending.callbacksCompleted) {
161- pending.stopPending()
162- }
163- return @listen
164- }
165-
166119 breakInfos
167120 .filterNotNull()
168121 .firstOrNull { it.context.expectedPos == event.pos }
@@ -185,15 +138,6 @@ object BreakManager : RequestHandler<BreakRequest>(
185138 // ToDo: Dependent on the tracked data order. When set stack is called after position it wont work
186139 listen<EntityEvent .EntityUpdate >(priority = Int .MIN_VALUE + 1 ) {
187140 if (it.entity !is ItemEntity ) return @listen
188- pendingBreaks
189- .firstOrNull { info -> matchesBlockItem(info, it.entity) }
190- ?.let { pending ->
191- pending.internalOnItemDrop(it.entity)
192- if (pending.callbacksCompleted) {
193- pending.stopPending()
194- }
195- return @listen
196- }
197141
198142 breakInfos
199143 .filterNotNull()
@@ -203,7 +147,6 @@ object BreakManager : RequestHandler<BreakRequest>(
203147
204148 listenUnsafe<ConnectionEvent .Connect .Pre >(priority = Int .MIN_VALUE + 1 ) {
205149 breakInfos.forEach { it?.nullify() }
206- pendingBreaks.clear()
207150 breakCooldown = 0
208151 }
209152 }
@@ -286,6 +229,20 @@ object BreakManager : RequestHandler<BreakRequest>(
286229 maxBreaksThisTick = breakConfig.breaksPerTick.coerceAtMost(pendingLimit)
287230 }
288231
232+ /* *
233+ * @return if the break context can be accepted.
234+ */
235+ private fun SafeContext.canAccept (ctx : BreakContext ): Boolean {
236+ if (pendingBreaks.any { it.context.expectedPos == ctx.expectedPos }) return false
237+
238+ breakInfos.firstOrNull { it != null && ! it.isRedundant }
239+ ?.let { info ->
240+ if ( ctx.hotbarIndex != info.context.hotbarIndex) return false
241+ }
242+
243+ return ! blockState(ctx.expectedPos).isAir
244+ }
245+
289246 /* *
290247 * Attempts to break as many [BreakContext]'s as possible from the [instantBreaks] collection within this tick.
291248 *
@@ -359,8 +316,7 @@ object BreakManager : RequestHandler<BreakRequest>(
359316 }
360317
361318 primaryBreak = breakInfo
362- pendingBreaks.setSizeLimit(request.build.breaking.maxPendingBreaks)
363- pendingBreaks.setDecayTime(request.build.interactionTimeout * 50L )
319+ setPendingConfigs(request)
364320 return primaryBreak
365321 }
366322
@@ -372,41 +328,6 @@ object BreakManager : RequestHandler<BreakRequest>(
372328 return breakInfos.take(possibleBreakingCount).all { it != null }
373329 }
374330
375- /* *
376- * @return if the [ItemEntity] matches the [BreakInfo]'s expected item drop.
377- */
378- private fun matchesBlockItem (info : BreakInfo , entity : ItemEntity ): Boolean {
379- val inRange = info.context.expectedPos.toCenterPos().isInRange(entity.pos, 0.5 )
380- val correctMaterial = info.context.checkedState.block == entity.stack.item.block
381- return inRange && correctMaterial
382- }
383-
384- /* *
385- * @return if the [newState] matches the [targetState].
386- *
387- * @see TargetState
388- */
389- private fun SafeContext.matchesTargetState (pos : BlockPos , targetState : TargetState , newState : BlockState ) =
390- if (targetState.matches(newState, pos, world)) true
391- else {
392- this @BreakManager.warn(" Break at ${pos.toShortString()} was rejected with $newState instead of $targetState " )
393- false
394- }
395-
396- /* *
397- * @return if the break context can be accepted.
398- */
399- private fun SafeContext.canAccept (ctx : BreakContext ): Boolean {
400- if (pendingBreaks.any { it.context.expectedPos == ctx.expectedPos }) return false
401-
402- breakInfos.firstOrNull { it != null && ! it.isRedundant }
403- ?.let { info ->
404- if ( ctx.hotbarIndex != info.context.hotbarIndex) return false
405- }
406-
407- return ! blockState(ctx.expectedPos).isAir
408- }
409-
410331 /* *
411332 * Begins the post-break logic sequence for the given [info].
412333 *
@@ -446,22 +367,6 @@ object BreakManager : RequestHandler<BreakRequest>(
446367 info.nullify()
447368 }
448369
449- /* *
450- * Adds the [info] to the break manager, and requesters, pending interaction collections.
451- */
452- private fun BreakInfo.startPending () {
453- pendingBreaks.add(this )
454- pendingInteractions.add(context)
455- }
456-
457- /* *
458- * Removes the [info] from the break manager, and requesters, pending interation collections.
459- */
460- private fun BreakInfo.stopPending () {
461- pendingBreaks.remove(this )
462- pendingInteractions.remove(context)
463- }
464-
465370 /* *
466371 * Makes the [BreakInfo] a secondary if not already.
467372 */
@@ -686,35 +591,25 @@ object BreakManager : RequestHandler<BreakRequest>(
686591 }
687592
688593 /* *
689- * A modified version of the minecraft breakBlock method.
690- *
691- * Performs the actions required to display break particles, sounds, texture overlay, etc.
692- * based on the users settings.
693- *
694- * @return if the blocks state was set or not.
695- *
696- * @see net.minecraft.client.world.ClientWorld.breakBlock
594+ * @return if the [ItemEntity] matches the [BreakInfo]'s expected item drop.
697595 */
698- private fun SafeContext.destroyBlock (info : BreakInfo ): Boolean {
699- val ctx = info.context
700-
701- if (player.isBlockBreakingRestricted(world, ctx.expectedPos, gamemode)) return false
702-
703- if (! player.mainHandStack.item.canMine(ctx.checkedState, world, ctx.expectedPos, player))
704- return false
705- val block = ctx.checkedState.block
706- if (block is OperatorBlock && ! player.isCreativeLevelTwoOp) return false
707- if (ctx.checkedState.isAir) return false
708-
709- block.onBreak(world, ctx.expectedPos, ctx.checkedState, player)
710- val fluidState = fluidState(ctx.expectedPos)
711- val setState = world.setBlockState(ctx.expectedPos, fluidState.blockState, 11 )
712- if (setState) block.onBroken(world, ctx.expectedPos, ctx.checkedState)
713-
714- if (info.breakConfig.breakingTexture) info.setBreakingTextureStage(player, world, - 1 )
715-
716- return setState
596+ fun matchesBlockItem (info : BreakInfo , entity : ItemEntity ): Boolean {
597+ val inRange = info.context.expectedPos.toCenterPos().isInRange(entity.pos, 0.5 )
598+ val correctMaterial = info.context.checkedState.block == entity.stack.item.block
599+ return inRange && correctMaterial
717600 }
718601
602+ /* *
603+ * @return if the [newState] matches the [targetState].
604+ *
605+ * @see TargetState
606+ */
607+ fun SafeContext.matchesTargetState (pos : BlockPos , targetState : TargetState , newState : BlockState ) =
608+ if (targetState.matches(newState, pos, world)) true
609+ else {
610+ this @BreakManager.warn(" Break at ${pos.toShortString()} was rejected with $newState instead of $targetState " )
611+ false
612+ }
613+
719614 override fun preEvent (): Event = UpdateManagerEvent .Break ().post()
720615}
0 commit comments