Skip to content

Commit 4492a04

Browse files
committed
start to re break implementation. Need to fix issue with managers calling other managers in onOpen before they have opened
1 parent d1d6568 commit 4492a04

File tree

9 files changed

+258
-63
lines changed

9 files changed

+258
-63
lines changed

common/src/main/kotlin/com/lambda/config/groups/BreakSettings.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class BreakSettings(
2929
vis: () -> Boolean = { true }
3030
) : BreakConfig(priority) {
3131
override val breakMode by c.setting("Break Mode", BreakMode.Packet) { vis() }
32+
override val reBreak = ReBreakSettings(c, vis)
3233
override val unsafeCancels by c.setting("Unsafe Cancels", true, "Allows cancelling block breaking even if the server might continue breaking sever side, potentially causing unexpected state changes") { vis() }
3334
override val breakThreshold by c.setting("Break Threshold", 0.7f, 0.1f..1.0f, 0.02f, "The break amount at which the block is considered broken") { vis() }
3435
override val doubleBreak by c.setting("Double Break", true, "Allows breaking two blocks at once") { vis() }
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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.config.groups
19+
20+
import com.lambda.config.Configurable
21+
22+
class ReBreakSettings(
23+
c: Configurable,
24+
vis: () -> Boolean = { true }
25+
) {
26+
val mode by c.setting("ReBreak Mode", Mode.Manual, "The method used to re-break blocks after they've been broken once", vis)
27+
28+
enum class Mode {
29+
None,
30+
Manual,
31+
Auto,
32+
AutoConstant;
33+
34+
fun isEnabled() = this != None
35+
}
36+
}

common/src/main/kotlin/com/lambda/event/events/TickEvent.kt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import com.lambda.event.Event
3737
*
3838
* @see net.minecraft.client.MinecraftClient.tick
3939
*/
40-
sealed class TickEvent {
40+
sealed class TickEvent : Event {
4141
/**
4242
* Triggered before each iteration of the game loop.
4343
*
@@ -47,12 +47,12 @@ sealed class TickEvent {
4747
* 2. Steps world tick manager
4848
* 3. Decrements item use cooldown
4949
*/
50-
data object Pre : Event
50+
data object Pre : TickEvent()
5151

5252
/**
5353
* Triggered after each iteration of the game loop.
5454
*/
55-
data object Post : Event
55+
data object Post : TickEvent()
5656

5757
/**
5858
* Triggered during the network tick stage only
@@ -69,8 +69,8 @@ sealed class TickEvent {
6969
* @see net.minecraft.client.network.ClientPlayerInteractionManager.tick
7070
*/
7171
sealed class Network {
72-
data object Pre : Event
73-
data object Post : Event
72+
data object Pre : TickEvent()
73+
data object Post : TickEvent()
7474
}
7575

7676
/**
@@ -87,8 +87,8 @@ sealed class TickEvent {
8787
* @see net.minecraft.client.MinecraftClient.handleInputEvents
8888
*/
8989
sealed class Input {
90-
data object Pre : Event
91-
data object Post : Event
90+
data object Pre : TickEvent()
91+
data object Post : TickEvent()
9292
}
9393

9494
/**
@@ -97,8 +97,8 @@ sealed class TickEvent {
9797
* @see net.minecraft.client.render.WorldRenderer.tick
9898
*/
9999
sealed class WorldRender {
100-
data object Pre : Event
101-
data object Post : Event
100+
data object Pre : TickEvent()
101+
data object Post : TickEvent()
102102
}
103103

104104
/**
@@ -107,8 +107,8 @@ sealed class TickEvent {
107107
* @see net.minecraft.client.sound.SoundManager.tick
108108
*/
109109
sealed class Sound {
110-
data object Pre : Event
111-
data object Post : Event
110+
data object Pre : TickEvent()
111+
data object Post : TickEvent()
112112
}
113113

114114
/**
@@ -128,12 +128,12 @@ sealed class TickEvent {
128128
/**
129129
* Triggered before each render tick ([TickEvent.Render]) of the game loop.
130130
*/
131-
data object Pre : Event
131+
data object Pre : TickEvent()
132132

133133
/**
134134
* Triggered after each render tick ([TickEvent.Render]) of the game loop.
135135
*/
136-
data object Post : Event
136+
data object Post : TickEvent()
137137
}
138138

139139
/**
@@ -152,11 +152,11 @@ sealed class TickEvent {
152152
/**
153153
* Triggered before each player tick ([TickEvent.Player]).
154154
*/
155-
data object Pre : Event
155+
data object Pre : TickEvent()
156156

157157
/**
158158
* Triggered after each player tick ([TickEvent.Player]).
159159
*/
160-
data object Post : Event
160+
data object Post : TickEvent()
161161
}
162162
}

common/src/main/kotlin/com/lambda/interaction/request/breaking/BreakConfig.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.lambda.interaction.request.breaking
1919

2020
import com.lambda.config.groups.BuildConfig
21+
import com.lambda.config.groups.ReBreakSettings
2122
import com.lambda.event.Event
2223
import com.lambda.interaction.request.Priority
2324
import com.lambda.interaction.request.RequestConfig
@@ -27,6 +28,7 @@ abstract class BreakConfig(
2728
priority: Priority = 0
2829
) : RequestConfig<BreakRequest>(priority) {
2930
abstract val breakMode: BreakMode
31+
abstract val reBreak: ReBreakSettings
3032
abstract val unsafeCancels: Boolean
3133
abstract val breakThreshold: Float
3234
abstract val doubleBreak: Boolean

common/src/main/kotlin/com/lambda/interaction/request/breaking/BreakInfo.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ data class BreakInfo(
4646
val isPrimary get() = type == BreakType.Primary
4747
val isSecondary get() = type == BreakType.Secondary
4848
val isRedundant get() = type == BreakType.RedundantSecondary
49+
val isReBreaking get() = type == BreakType.ReBreak
4950

5051
@Volatile
5152
var broken = false; private set
@@ -84,6 +85,11 @@ data class BreakInfo(
8485
}
8586
}
8687

88+
fun resetCallbacks() {
89+
broken = false
90+
item = null
91+
}
92+
8793
fun setBreakingTextureStage(
8894
player: ClientPlayerEntity,
8995
world: ClientWorld,
@@ -123,7 +129,8 @@ data class BreakInfo(
123129
enum class BreakType(val index: Int) {
124130
Primary(0),
125131
Secondary(1),
126-
RedundantSecondary(2);
132+
RedundantSecondary(2),
133+
ReBreak(2);
127134

128135
fun getBreakThreshold(breakConfig: BreakConfig) =
129136
when (this) {

common/src/main/kotlin/com/lambda/interaction/request/breaking/BreakManager.kt

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import com.lambda.event.events.WorldEvent
2828
import com.lambda.event.listener.SafeListener.Companion.listen
2929
import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe
3030
import com.lambda.interaction.construction.context.BreakContext
31-
import com.lambda.interaction.construction.verify.TargetState
3231
import com.lambda.interaction.request.PositionBlocking
3332
import com.lambda.interaction.request.Priority
3433
import com.lambda.interaction.request.RequestHandler
@@ -37,7 +36,10 @@ import com.lambda.interaction.request.breaking.BreakConfig.BreakMode
3736
import com.lambda.interaction.request.breaking.BreakManager.activeRequest
3837
import com.lambda.interaction.request.breaking.BreakManager.processRequest
3938
import com.lambda.interaction.request.breaking.BreakType.Primary
39+
import com.lambda.interaction.request.breaking.BreakType.ReBreak
40+
import com.lambda.interaction.request.breaking.BrokenBlockHandler.brokenState
4041
import com.lambda.interaction.request.breaking.BrokenBlockHandler.destroyBlock
42+
import com.lambda.interaction.request.breaking.BrokenBlockHandler.isBroken
4143
import com.lambda.interaction.request.breaking.BrokenBlockHandler.pendingBreaks
4244
import com.lambda.interaction.request.breaking.BrokenBlockHandler.setPendingConfigs
4345
import com.lambda.interaction.request.breaking.BrokenBlockHandler.startPending
@@ -50,7 +52,6 @@ import com.lambda.util.Communication.warn
5052
import com.lambda.util.item.ItemUtils.block
5153
import com.lambda.util.player.gamemode
5254
import com.lambda.util.player.swingHand
53-
import net.minecraft.block.BlockState
5455
import net.minecraft.client.sound.PositionedSoundInstance
5556
import net.minecraft.client.sound.SoundInstance
5657
import net.minecraft.entity.ItemEntity
@@ -85,12 +86,14 @@ object BreakManager : RequestHandler<BreakRequest>(
8586
private val rotated get() = rotationRequest?.done != false
8687

8788
private var breakCooldown = 0
88-
private var breaksThisTick = 0
89+
var breaksThisTick = 0
8990
private var maxBreaksThisTick = 0
9091

9192
private var breaks = mutableListOf<BreakContext>()
9293
private var instantBreaks = mutableListOf<BreakContext>()
9394

95+
var lastPosStarted: BlockPos? = null
96+
9497
fun Any.onBreak(
9598
alwaysListen: Boolean = false,
9699
priority: Priority = 0,
@@ -126,7 +129,8 @@ object BreakManager : RequestHandler<BreakRequest>(
126129
.firstOrNull { it.context.expectedPos == event.pos }
127130
?.let { info ->
128131
// if not broken
129-
if (!matchesTargetState(event.pos, info.context.targetState, event.newState)) {
132+
if (!isBroken(info.context.checkedState, event.newState)) {
133+
this@BreakManager.warn("Break at ${event.pos.toShortString()} was rejected with ${event.newState} instead of ${info.context.checkedState.brokenState}")
130134
// update the checked state
131135
info.context.checkedState = event.newState
132136
return@listen
@@ -135,6 +139,8 @@ object BreakManager : RequestHandler<BreakRequest>(
135139
info.internalOnBreak()
136140
if (!info.callbacksCompleted) {
137141
info.startPending()
142+
} else if (info.isPrimary) {
143+
ReBreakManager.startReBreak(info)
138144
}
139145
info.nullify()
140146
}
@@ -387,6 +393,8 @@ object BreakManager : RequestHandler<BreakRequest>(
387393
info.internalOnBreak()
388394
if (!info.callbacksCompleted) {
389395
info.startPending()
396+
} else if (info.isPrimary) {
397+
ReBreakManager.startReBreak(info)
390398
}
391399
}
392400
BreakConfirmationMode.BreakThenAwait -> {
@@ -442,7 +450,7 @@ object BreakManager : RequestHandler<BreakRequest>(
442450
*/
443451
private fun BreakInfo.nullify() {
444452
type.nullify()
445-
if (!broken) internalOnCancel()
453+
if (!broken && !isReBreaking && !isRedundant) internalOnCancel()
446454
}
447455

448456
/**
@@ -458,7 +466,8 @@ object BreakManager : RequestHandler<BreakRequest>(
458466
*/
459467
private fun BreakType.nullify() =
460468
when (this) {
461-
Primary -> primaryBreak = null
469+
Primary,
470+
ReBreak -> primaryBreak = null
462471
else -> secondaryBreak = null
463472
}
464473

@@ -492,10 +501,29 @@ object BreakManager : RequestHandler<BreakRequest>(
492501
}
493502

494503
if (!info.breaking) {
504+
when (val reBreakResult = ReBreakManager.handleUpdate(info.context, info.request)) {
505+
is ReBreakResult.StillBreaking -> {
506+
primaryBreak = reBreakResult.breakInfo.apply {
507+
type = Primary
508+
ReBreakManager.clearReBreak()
509+
}
510+
511+
primaryBreak?.let { primary ->
512+
updateBreakProgress(primary)
513+
}
514+
return true
515+
}
516+
is ReBreakResult.ReBroke -> {
517+
info.nullify()
518+
return true
519+
}
520+
else -> {}
521+
}
495522
if (!startBreaking(info)) {
496523
info.nullify()
497524
return false
498525
}
526+
ReBreakManager.clearReBreak()
499527
val swing = info.breakConfig.swing
500528
if (swing.isEnabled() && swing != BreakConfig.SwingMode.End) {
501529
swingHand(info.breakConfig.swingType, Hand.MAIN_HAND)
@@ -616,6 +644,7 @@ object BreakManager : RequestHandler<BreakRequest>(
616644
if (info.breakConfig.breakMode == BreakMode.Packet) {
617645
info.stopBreakPacket(world, interaction)
618646
}
647+
lastPosStarted = ctx.expectedPos
619648
info.startBreakPacket(world, interaction)
620649
if (info.isSecondary || (breakDelta < 1 && breakDelta >= info.breakConfig.breakThreshold)) {
621650
info.stopBreakPacket(world, interaction)
@@ -633,17 +662,5 @@ object BreakManager : RequestHandler<BreakRequest>(
633662
return inRange && correctMaterial
634663
}
635664

636-
/**
637-
* @return if the [newState] matches the [targetState].
638-
*
639-
* @see TargetState
640-
*/
641-
fun SafeContext.matchesTargetState(pos: BlockPos, targetState: TargetState, newState: BlockState) =
642-
if (targetState.matches(newState, pos, world)) true
643-
else {
644-
this@BreakManager.warn("Break at ${pos.toShortString()} was rejected with $newState instead of $targetState")
645-
false
646-
}
647-
648665
override fun preEvent(): Event = UpdateManagerEvent.Break().post()
649666
}

0 commit comments

Comments
 (0)