Skip to content

Commit 2832bb5

Browse files
committed
fix blocks that break at a faster speed, causing unfortunate timing collisions
1 parent 72dc508 commit 2832bb5

6 files changed

Lines changed: 74 additions & 74 deletions

File tree

src/main/kotlin/com/lambda/interaction/handlers/breaking/BrokenBlockHandler.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import com.lambda.event.events.EntityEvent
2424
import com.lambda.event.events.WorldEvent
2525
import com.lambda.event.listener.SafeListener.Companion.listen
2626
import com.lambda.interaction.construction.simulation.processing.ProcessorRegistry
27-
import com.lambda.interaction.handlers.breaking.RebreakHandler.rebreak
27+
import com.lambda.interaction.handlers.breaking.RebreakHandler.reBreak
2828
import com.lambda.interaction.managers.PostActionHandler
2929
import com.lambda.interaction.managers.breaking.BreakInfo
3030
import com.lambda.interaction.managers.breaking.BreakManager.lastPosStarted
@@ -82,7 +82,7 @@ object BrokenBlockHandler : PostActionHandler<BreakInfo>() {
8282
listen<WorldEvent.BlockUpdate.Server>({ Int.MIN_VALUE }) { event ->
8383
run {
8484
pendingActions.firstOrNull { it.context.blockPos == event.pos }
85-
?: if (rebreak?.context?.blockPos == event.pos) rebreak
85+
?: if (reBreak?.context?.blockPos == event.pos) reBreak
8686
else null
8787
}?.let { pending ->
8888
val currentState = pending.context.cachedState
@@ -126,7 +126,7 @@ object BrokenBlockHandler : PostActionHandler<BreakInfo>() {
126126
if (entity !is ItemEntity) return@runGameScheduled
127127
val pending =
128128
pendingActions.firstOrNull { info -> matchesBlockItem(info, entity) }
129-
?: rebreak?.let { info ->
129+
?: reBreak?.let { info ->
130130
if (matchesBlockItem(info, entity)) info
131131
else return@runGameScheduled
132132
} ?: return@runGameScheduled

src/main/kotlin/com/lambda/interaction/handlers/breaking/RebreakHandler.kt

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import com.lambda.event.listener.SafeListener.Companion.listen
2525
import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe
2626
import com.lambda.interaction.construction.simulation.context.BreakContext
2727
import com.lambda.interaction.handlers.breaking.BrokenBlockHandler.destroyBlock
28-
import com.lambda.interaction.handlers.breaking.RebreakHandler.rebreak
28+
import com.lambda.interaction.handlers.breaking.RebreakHandler.reBreak
2929
import com.lambda.interaction.handlers.packet.PacketLimitHandler
3030
import com.lambda.interaction.handlers.packet.PacketType
3131
import com.lambda.interaction.managers.breaking.BreakInfo
@@ -41,11 +41,11 @@ import net.minecraft.util.Hand
4141
* the user to break any block placed in said position using the progress from the previously broken block.
4242
*/
4343
object RebreakHandler {
44-
var rebreak: BreakInfo? = null
44+
var reBreak: BreakInfo? = null
4545

4646
init {
4747
listen<TickEvent.Post>({ Int.MIN_VALUE + 1 }) {
48-
rebreak?.run {
48+
reBreak?.run {
4949
if (!progressedThisTick) {
5050
breakingTicks++
5151
progressedThisTick = true
@@ -54,19 +54,19 @@ object RebreakHandler {
5454
}
5555

5656
listenUnsafe<ConnectionEvent.Connect.Pre>({ Int.MIN_VALUE }) {
57-
rebreak = null
57+
reBreak = null
5858
}
5959
}
6060

6161
/**
6262
* Tests to see if the [BreakInfo] can be accepted. If not, nothing happens. Otherwise,
63-
* the [rebreak] is set, and the [com.lambda.interaction.managers.breaking.BreakRequest.onReBreakStart] callback is invoked.
63+
* the [reBreak] is set, and the [com.lambda.interaction.managers.breaking.BreakRequest.onReBreakStart] callback is invoked.
6464
*/
6565
context(safeContext: SafeContext)
6666
fun offerRebreak(info: BreakInfo) {
6767
if (!info.rebreakable) return
6868

69-
rebreak = info.apply {
69+
reBreak = info.apply {
7070
type = BreakInfo.BreakType.Rebreak
7171
breaking = true
7272
resetCallbacks()
@@ -75,7 +75,7 @@ object RebreakHandler {
7575
}
7676

7777
fun clearRebreak() {
78-
rebreak = null
78+
reBreak = null
7979
}
8080

8181
/**
@@ -89,11 +89,11 @@ object RebreakHandler {
8989
*/
9090
context(_: SafeContext)
9191
fun BreakInfo.getRebreakPotential() = request.runSafeAutomated {
92-
rebreak?.let { reBreak ->
92+
reBreak?.let { reBreak ->
9393
val stack = if (breakConfig.swapMode.isEnabled())
9494
swapStack
9595
else player.mainHandStack
96-
val breakDelta = context.cachedState.calcBreakDelta(context.blockPos, stack)
96+
val breakDelta = calcBreakDelta(stack)
9797
val possible = reBreak.breakConfig.rebreak &&
9898
context.blockPos == reBreak.context.blockPos
9999
val instant = (reBreak.breakingTicks - breakConfig.fudgeFactor) * breakDelta >= breakConfig.breakThreshold
@@ -106,18 +106,17 @@ object RebreakHandler {
106106
}
107107

108108
/**
109-
* Updates the current [rebreak] with a fresh [BreakContext], and attempts to rebreak the block if possible.
109+
* Updates the current [reBreak] with a fresh [BreakContext], and attempts to rebreak the block if possible.
110110
*
111111
* @return A [RebreakResult] to indicate how the update has been processed.
112112
*/
113113
context(_: SafeContext)
114114
fun handleUpdate(ctx: BreakContext, request: BreakRequest) = request.runSafeAutomated {
115-
val reBreak = this@RebreakHandler.rebreak ?: return@runSafeAutomated RebreakResult.Ignored
115+
val reBreak = this@RebreakHandler.reBreak ?: return@runSafeAutomated RebreakResult.Ignored
116116

117117
reBreak.updateInfo(ctx, request)
118118

119-
val context = reBreak.context
120-
val breakDelta = context.cachedState.calcBreakDelta(context.blockPos)
119+
val breakDelta = reBreak.calcBreakDelta()
121120
val breakTicks = reBreak.breakingTicks - breakConfig.fudgeFactor
122121
return@runSafeAutomated if (breakTicks * breakDelta >= reBreak.getBreakThreshold()) {
123122
if (!PacketLimitHandler.canSendPackets(1, PacketType.PlayerAction)) return@runSafeAutomated RebreakResult.Ignored

src/main/kotlin/com/lambda/interaction/managers/breaking/BreakInfo.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import net.minecraft.item.ItemStack
3636
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket
3737
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket.Action
3838
import net.minecraft.util.math.BlockPos
39-
import net.minecraft.world.attribute.EnvironmentAttributeModifier.override
4039

4140
/**
4241
* A data class that holds all the information required to process and continue a break.
@@ -130,7 +129,7 @@ data class BreakInfo(
130129
val item =
131130
if (breakConfig.swapMode.isEnabled() && breakConfig.swapMode != BreakConfig.SwapMode.Start) swapStack
132131
else player.mainHandStack
133-
val breakDelta = request.runSafeAutomated { context.cachedState.calcBreakDelta(context.blockPos, item) }
132+
val breakDelta = request.runSafeAutomated { calcBreakDelta(item) }
134133
val progress = (breakDelta * breakingTicks) / (getBreakThreshold() + (breakDelta * breakConfig.fudgeFactor))
135134
return if (progress > 0.0f) (progress * 10.0f).toInt().coerceAtMost(9) else -1
136135
}

src/main/kotlin/com/lambda/interaction/managers/breaking/BreakManager.kt

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ import com.lambda.interaction.material.StackSelection.Companion.select
7878
import com.lambda.threading.runGameScheduled
7979
import com.lambda.threading.runSafe
8080
import com.lambda.threading.runSafeAutomated
81-
import com.lambda.util.BlockUtils.blockState
8281
import com.lambda.util.BlockUtils.calcItemBlockBreakingDelta
8382
import com.lambda.util.BlockUtils.isEmpty
8483
import com.lambda.util.BlockUtils.isNotBroken
@@ -88,7 +87,6 @@ import com.lambda.util.item.ItemUtils.block
8887
import com.lambda.util.math.lerp
8988
import com.lambda.util.player.PlayerUtils.gamemode
9089
import com.lambda.util.player.PlayerUtils.swingHand
91-
import net.minecraft.block.BlockState
9290
import net.minecraft.client.sound.PositionedSoundInstance
9391
import net.minecraft.client.sound.SoundInstance
9492
import net.minecraft.entity.ItemEntity
@@ -181,7 +179,7 @@ object BreakManager : Manager<BreakRequest>(
181179
}
182180

183181
listen<WorldEvent.BlockUpdate.Server>({ Int.MIN_VALUE }) { event ->
184-
if (event.pos == RebreakHandler.rebreak?.context?.blockPos) return@listen
182+
if (event.pos == RebreakHandler.reBreak?.context?.blockPos) return@listen
185183

186184
breakInfos
187185
.firstOrNull { it?.context?.blockPos == event.pos }
@@ -213,7 +211,7 @@ object BreakManager : Manager<BreakRequest>(
213211
if (entity !is ItemEntity) return@runGameScheduled
214212

215213
// ToDo: Proper item drop prediction system
216-
RebreakHandler.rebreak?.let { reBreak ->
214+
RebreakHandler.reBreak?.let { reBreak ->
217215
if (matchesBlockItem(reBreak, entity)) return@runGameScheduled
218216
}
219217

@@ -244,16 +242,11 @@ object BreakManager : Manager<BreakRequest>(
244242
val config = info.breakConfig
245243
if (!config.renders) return@immediateRenderer
246244
val swapMode = config.swapMode
247-
val breakDelta = info.request.runSafeAutomated {
248-
info.context.cachedState.calcBreakDelta(
249-
info.context.blockPos,
250-
if (info.type != RedundantSecondary &&
251-
swapMode.isEnabled() &&
252-
swapMode != BreakConfig.SwapMode.Start
253-
) activeStack
254-
else null
255-
).toDouble()
256-
}
245+
val breakDelta =
246+
info.request.runSafeAutomated {
247+
val useActiveStack = info.type != RedundantSecondary && swapMode.isEnabled() && swapMode != BreakConfig.SwapMode.Start
248+
info.calcBreakDelta(if (useActiveStack) activeStack else player.mainHandStack).toDouble()
249+
}
257250
val currentDelta = info.breakingTicks * breakDelta
258251

259252
val threshold = if (info.type == Primary) config.breakThreshold else 1f
@@ -263,18 +256,15 @@ object BreakManager : Manager<BreakRequest>(
263256
val nextTicksProgress = (currentDelta + breakDelta) / adjustedThreshold
264257
val interpolatedProgress = lerp(mc.tickDelta, currentProgress, nextTicksProgress)
265258

266-
val fillColor = if (config.dynamicFillColor) lerp(
267-
interpolatedProgress,
268-
config.startFillColor,
269-
config.endFillColor
270-
)
271-
else config.staticFillColor
272-
val outlineColor = if (config.dynamicOutlineColor) lerp(
273-
interpolatedProgress,
274-
config.startOutlineColor,
275-
config.endOutlineColor
276-
)
277-
else config.staticOutlineColor
259+
val fillColor =
260+
if (config.dynamicFillColor)
261+
lerp(interpolatedProgress, config.startFillColor, config.endFillColor)
262+
else config.staticFillColor
263+
264+
val outlineColor =
265+
if (config.dynamicOutlineColor)
266+
lerp(interpolatedProgress, config.startOutlineColor, config.endOutlineColor)
267+
else config.staticOutlineColor
278268

279269
val pos = info.context.blockPos
280270
info.context.cachedState.getOutlineShape(world, pos).boundingBoxes.map {
@@ -471,9 +461,9 @@ object BreakManager : Manager<BreakRequest>(
471461
request.runSafeAutomated {
472462
if (tickStage !in request.breakConfig.tickStageMask) return false
473463
if (breakDelay > 0) return false
464+
if (breaksThisTick >= maxBreaksThisTick) return false
474465

475466
breaks.forEach { ctx ->
476-
if (breaksThisTick >= maxBreaksThisTick) return false
477467
if (!currentStackSelection.filterStack(player.inventory.getStack(ctx.hotbarIndex))) return@forEach
478468

479469
initNewBreak(ctx, request) ?: return false
@@ -503,21 +493,32 @@ object BreakManager : Manager<BreakRequest>(
503493
request: BreakRequest
504494
): BreakInfo? {
505495
val breakInfo = BreakInfo(requestCtx, Primary, request)
506-
primaryBreak?.let { primaryInfo ->
507-
if (tickStage !in primaryInfo.breakConfig.tickStageMask) return null
496+
primaryBreak?.let { primary ->
497+
val primaryConfig = primary.breakConfig
498+
if (tickStage !in primaryConfig.tickStageMask) return null
508499
if (!PacketLimitHandler.canSendPackets(1, PacketType.PlayerAction)) return null
509500

510-
if (!primaryInfo.breakConfig.doubleBreak || secondaryBreak != null) {
511-
if (!primaryInfo.updatedThisTick) {
512-
primaryInfo.cancelBreak()
501+
if (!primaryConfig.doubleBreak || secondaryBreak != null) {
502+
if (!primary.updatedThisTick) {
503+
primary.cancelBreak()
513504
return@let
514505
} else return null
515506
}
516507

517-
if (!primaryInfo.breaking) return null
508+
if (!primary.breaking) return null
518509

519-
secondaryBreak = primaryInfo.apply { type = Secondary }
520-
secondaryBreak?.stopBreakPacket()
510+
if (primaryConfig.breakMode == BreakMode.OldGrim) {
511+
val breakDelta = primary.calcBreakDelta()
512+
val extraTick = !primary.progressedThisTick
513+
val ticks = primary.breakingTicks.let { if (extraTick) it + 1 else it }
514+
if (ticks * breakDelta >= primaryConfig.breakThreshold) return null
515+
}
516+
517+
secondaryBreak =
518+
primary.apply {
519+
type = Secondary
520+
stopBreakPacket()
521+
}
521522
PacketLimitHandler.sentPackets(1, PacketType.PlayerAction)
522523
return@let
523524
}
@@ -563,7 +564,7 @@ object BreakManager : Manager<BreakRequest>(
563564
return@forEach
564565
}
565566
info.request.runSafeAutomated {
566-
val breakDelta = cachedState.calcBreakDelta(info.context.blockPos, player.mainHandStack)
567+
val breakDelta = info.calcBreakDelta()
567568
val ticksToBreak = 1.0 / breakDelta
568569
val ticksPast = info.breakingTicks - ticksToBreak
569570
if (ticksPast >= 200) {
@@ -709,7 +710,7 @@ object BreakManager : Manager<BreakRequest>(
709710
return
710711
}
711712

712-
val blockState = blockState(ctx.blockPos)
713+
val blockState = ctx.cachedState
713714
if (blockState.isEmpty) {
714715
info.nullify()
715716
info.request.onCancel?.invoke(this, ctx.blockPos)
@@ -718,15 +719,16 @@ object BreakManager : Manager<BreakRequest>(
718719

719720
if (breakConfig.swapMode == BreakConfig.SwapMode.Constant && !swapped) return
720721

722+
info.breakingTicks++
723+
721724
val requiresDelayBypassing = info.type == Primary && breakConfig.breakMode == BreakMode.OldGrim && !info.bypassedDelay
722-
if (requiresDelayBypassing && PacketLimitHandler.canSendPackets(22, PacketType.PlayerAction) && info.breakingTicks >= 6) {
725+
if (requiresDelayBypassing && PacketLimitHandler.canSendPackets(22, PacketType.PlayerAction) && info.breakingTicks > 6) {
723726
repeat(22) { info.startBreakPacket(OLD_GRIM_Y_OFFSET) }
724727
PacketLimitHandler.sentPackets(22, PacketType.PlayerAction)
725728
info.bypassedDelay = true
726729
}
727730

728-
info.breakingTicks++
729-
val breakDelta = blockState.calcBreakDelta(ctx.blockPos)
731+
val breakDelta = info.calcBreakDelta()
730732
val progress = breakDelta * (info.breakingTicks - breakConfig.fudgeFactor)
731733

732734
if (breakConfig.sounds) {
@@ -754,7 +756,7 @@ object BreakManager : Manager<BreakRequest>(
754756
if (info.swapInfo.swap && !swapped) return
755757

756758
if (info.type == Primary) {
757-
if (breakConfig.breakMode == BreakMode.OldGrim && info.breakingTicks < 6) return
759+
if (breakConfig.breakMode == BreakMode.OldGrim && info.breakingTicks <= 6) return
758760
if (!PacketLimitHandler.canSendPackets(1, PacketType.PlayerAction)) return
759761
}
760762

@@ -819,8 +821,7 @@ object BreakManager : Manager<BreakRequest>(
819821
}
820822
if (info.breaking) return false
821823

822-
val blockState = blockState(ctx.blockPos)
823-
val progress = blockState.calcBreakDelta(ctx.blockPos)
824+
val progress = info.calcBreakDelta()
824825
val instantBreakable = progress >= info.getBreakThreshold()
825826

826827
var packetCount = 1
@@ -840,7 +841,7 @@ object BreakManager : Manager<BreakRequest>(
840841
lastPosStarted = ctx.blockPos
841842

842843
if (info.breakingTicks == 0) {
843-
blockState.onBlockBreakStart(world, ctx.blockPos, player)
844+
info.context.cachedState.onBlockBreakStart(world, ctx.blockPos, player)
844845
}
845846

846847
if (instantBreakable) onBlockBreak(info)
@@ -871,11 +872,10 @@ object BreakManager : Manager<BreakRequest>(
871872
* Wrapper method for calculating block-breaking delta.
872873
*/
873874
context(automatedSafeContext: AutomatedSafeContext)
874-
fun BlockState.calcBreakDelta(
875-
pos: BlockPos,
876-
item: ItemStack? = null
875+
fun BreakInfo.calcBreakDelta(
876+
item: ItemStack = automatedSafeContext.player.mainHandStack
877877
) = with(automatedSafeContext) {
878-
val delta = calcItemBlockBreakingDelta( pos, item ?: player.mainHandStack)
878+
val delta = context.cachedState.calcItemBlockBreakingDelta(context.blockPos, item)
879879
//ToDo: This setting requires some fixes / improvements in the player movement prediction to work properly. Currently, it's broken
880880
// if (config.desyncFix) {
881881
// val nextTickPrediction = buildPlayerPrediction().next()

src/main/kotlin/com/lambda/interaction/managers/breaking/SwapInfo.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ data class SwapInfo(
4444
*/
4545
context(_: SafeContext)
4646
fun BreakInfo.getSwapInfo() = request.runSafeAutomated {
47-
val breakDelta = context.cachedState.calcBreakDelta(context.blockPos, swapStack)
47+
val breakDelta = calcBreakDelta(swapStack)
4848

4949
val threshold = getBreakThreshold()
5050

5151
// Plus one as this is calculated before this ticks' progress is calculated and the breakingTicks are incremented
52-
val breakTicks = (if (rebreakPotential.isPossible()) RebreakHandler.rebreak?.breakingTicks
52+
val breakTicks = (if (rebreakPotential.isPossible()) RebreakHandler.reBreak?.breakingTicks
5353
?: throw IllegalStateException("Rebreak BreakInfo was null when rebreak was considered possible")
5454
else breakingTicks) + 1 - breakConfig.fudgeFactor
5555

src/main/kotlin/com/lambda/util/BlockUtils.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ import net.minecraft.util.math.EightWayDirection
9999
import net.minecraft.util.math.Vec3d
100100
import net.minecraft.util.math.Vec3i
101101

102+
@Suppress("unused")
102103
object BlockUtils {
103104
val signs = setOf(
104105
Blocks.OAK_SIGN,
@@ -292,13 +293,14 @@ object BlockUtils {
292293
}
293294

294295
context(safeContext: SafeContext)
295-
fun BlockState.calcItemBlockBreakingDelta(blockPos: BlockPos, stack: ItemStack): Float = with(safeContext) {
296-
val hardness = getHardness(world, blockPos)
297-
return if (hardness == -1.0f) 0.0f else {
298-
val harvestMultiplier = if (stack.canHarvest(this@calcItemBlockBreakingDelta)) 30 else 100
299-
player.getItemBlockBreakingSpeed(this@calcItemBlockBreakingDelta, stack) / hardness / harvestMultiplier
296+
fun BlockState.calcItemBlockBreakingDelta(blockPos: BlockPos, stack: ItemStack): Float =
297+
with(safeContext) {
298+
val hardness = getHardness(world, blockPos)
299+
return if (hardness == -1.0f) 0.0f else {
300+
val harvestMultiplier = if (stack.canHarvest(this@calcItemBlockBreakingDelta)) 30 else 100
301+
player.getItemBlockBreakingSpeed(this@calcItemBlockBreakingDelta, stack) / hardness / harvestMultiplier
302+
}
300303
}
301-
}
302304

303305
fun ItemStack.canHarvest(state: BlockState) =
304306
!state.isToolRequired || isSuitableFor(state)

0 commit comments

Comments
 (0)