Skip to content

Commit c2dd7d7

Browse files
committed
replacement blocks for solid target state, and fixed race condition issue in place checker
1 parent eee5af4 commit c2dd7d7

File tree

7 files changed

+54
-59
lines changed

7 files changed

+54
-59
lines changed

src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ object BuildSimulator : SimChecker<PostSimResult>() {
5151
with(null) {
5252
if (checkRequirements() ||
5353
checkPostProcessing() ||
54-
checkPlacements() ||
55-
checkBreaks()) return@launch
54+
checkBreaks() ||
55+
checkPlacements()) return@launch
5656
else result(PostSimResult.NoMatch(pos))
5757
}
5858
}

src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakChecker.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import com.lambda.threading.runSafe
5050
import com.lambda.util.BlockUtils.blockState
5151
import com.lambda.util.BlockUtils.calcItemBlockBreakingDelta
5252
import com.lambda.util.BlockUtils.instantBreakable
53+
import com.lambda.util.BlockUtils.isEmpty
5354
import com.lambda.util.item.ItemStackUtils.inventoryIndexOrSelected
5455
import com.lambda.util.math.distSq
5556
import com.lambda.util.world.raycast.RayCastUtils.blockResult
@@ -87,6 +88,7 @@ class BreakChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
8788
val stackSelection: StackSelection by lazy {
8889
runSafe {
8990
selectStack(
91+
count = 0,
9092
sorter = compareByDescending<ItemStack> {
9193
it.canBreak(CachedBlockPosition(world, pos, false))
9294
}.thenByDescending {
@@ -131,8 +133,6 @@ class BreakChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
131133
}
132134

133135
private suspend fun AutomatedSafeContext.checkBreaks(): Boolean {
134-
if (!targetState.isEmpty()) return false
135-
136136
/* player is standing on top of the block */
137137
if (breakConfig.avoidSupporting) player.supportingBlockPos.getOrNull()?.let { support ->
138138
if (support != pos) return@let
@@ -143,9 +143,11 @@ class BreakChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
143143
/* liquid needs to be submerged first to be broken */
144144
if (targetState.getState(pos).isAir && !state.fluidState.isEmpty && state.isReplaceable) {
145145
result(BreakResult.Submerge(pos, state))
146-
return simInfo(pos, state, TargetState.Solid)?.checkPlacements() ?: true
146+
return simInfo(pos, state, TargetState.Solid(emptySet()))?.checkPlacements() ?: true
147147
}
148148

149+
if (state.isEmpty) return false
150+
149151
if (breakConfig.avoidLiquids && affectsFluids()) return true
150152

151153
val voxelShape = state.getOutlineShape(world, pos)
@@ -159,11 +161,9 @@ class BreakChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
159161
breakConfig.breakThreshold
160162
)
161163

162-
val currentRotation = RotationManager.activeRotation
163-
val currentCast = currentRotation.rayCast(buildConfig.interactReach, eye)
164-
165164
/* the player is buried inside the block */
166165
if (boxes.any { it.contains(eye) }) {
166+
val currentCast = RotationManager.activeRotation.rayCast(buildConfig.interactReach, eye)
167167
currentCast?.blockResult?.let { blockHit ->
168168
val rotationRequest = RotationRequest(lookAtBlock(pos), this)
169169
val breakContext = BreakContext(
@@ -336,7 +336,7 @@ class BreakChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
336336

337337
affectedFluids.forEach { (liquidPos, liquidState) ->
338338
result(BreakResult.Submerge(liquidPos, liquidState))
339-
simInfo(liquidPos, liquidState, TargetState.Solid)?.checkPlacements()
339+
simInfo(liquidPos, liquidState, TargetState.Solid(emptySet()))?.checkPlacements()
340340
}
341341
result(BreakResult.BlockedByFluid(pos, state))
342342
return true

src/main/kotlin/com/lambda/interaction/construction/simulation/checks/PlaceChecker.kt

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import com.lambda.interaction.material.ContainerSelection.Companion.selectContai
3333
import com.lambda.interaction.material.StackSelection.Companion.select
3434
import com.lambda.interaction.material.container.ContainerManager.containerWithMaterial
3535
import com.lambda.interaction.material.container.MaterialContainer
36+
import com.lambda.interaction.request.rotating.Rotation
3637
import com.lambda.interaction.request.rotating.Rotation.Companion.rotation
3738
import com.lambda.interaction.request.rotating.Rotation.Companion.rotationTo
3839
import com.lambda.interaction.request.rotating.RotationManager
@@ -78,9 +79,6 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
7879
: SimChecker<PlaceResult>(), Dependable,
7980
ISimInfo by simInfo
8081
{
81-
lateinit var resultState: BlockState
82-
var rot = RotationManager.serverRotation
83-
8482
private val swapStack by lazy {
8583
runSafeAutomated {
8684
val optimalStack = targetState.getStack(pos)
@@ -104,8 +102,6 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
104102
}
105103
private val blockItem get() = swapStack.blockItem
106104

107-
private var currentDirIsValid = false
108-
109105
override fun asDependent(buildResult: BuildResult) =
110106
PlaceResult.Dependency(pos, buildResult)
111107

@@ -120,8 +116,6 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
120116
}
121117

122118
private suspend fun AutomatedSafeContext.checkPlacements(): Boolean {
123-
if (targetState.isEmpty()) return false
124-
125119
supervisorScope {
126120
withContext(Dispatchers.Default) {
127121
preProcessing.sides.map { side ->
@@ -155,7 +149,7 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
155149
val misses = mutableSetOf<Vec3d>()
156150
val reachSq = buildConfig.interactReach.pow(2)
157151

158-
// ToDo: For each hand and sneak or not?
152+
// ToDo: For each hand
159153
val fakePlayer = copyPlayer(player).apply {
160154
this.rotation = RotationManager.serverRotation
161155
if (testBlockState.block::class in BlockUtils.interactionBlocks) {
@@ -249,22 +243,23 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
249243
return
250244
}
251245

252-
if (!simRotation(fakePlayer, checkedHit, context)) return
246+
val rotatePlaceTest = simRotatePlace(fakePlayer, checkedHit, context) ?: return
247+
if (!rotatePlaceTest.isValid) return
253248

254249
val rotationRequest = if (placeConfig.axisRotate) {
255-
lookInDirection(PlaceDirection.fromRotation(rot))
256-
} else lookAt(rot, 0.001)
250+
lookInDirection(PlaceDirection.fromRotation(rotatePlaceTest.rotation))
251+
} else lookAt(rotatePlaceTest.rotation, 0.001)
257252

258253
val placeContext = PlaceContext(
259254
hitResult,
260255
RotationRequest(rotationRequest, this@PlaceChecker),
261256
swapStack.inventoryIndex,
262257
pos,
263258
state,
264-
resultState,
259+
rotatePlaceTest.placeTest.resultState,
265260
fakePlayer.isSneaking,
266261
false,
267-
currentDirIsValid,
262+
rotatePlaceTest.currentDirIsValid,
268263
this@PlaceChecker
269264
)
270265

@@ -274,61 +269,64 @@ class PlaceChecker @SimCheckerDsl private constructor(simInfo: SimInfo)
274269
return
275270
}
276271

277-
private fun SafeContext.simRotation(
272+
private fun SafeContext.simRotatePlace(
278273
fakePlayer: ClientPlayerEntity,
279274
checkedHit: CheckedHit,
280275
context: ItemPlacementContext
281-
): Boolean {
282-
currentDirIsValid = if (testPlaceState(context) != PlaceTestResult.Success) {
283-
if (!placeConfig.rotateForPlace) return false
284-
else false
285-
} else true
276+
): RotatePlaceTest? {
277+
val currentDirIsValid = testPlaceState(context).let { currentDirTest ->
278+
if (currentDirTest.testResult != PlaceTestResult.Success) {
279+
if (!placeConfig.rotateForPlace)
280+
return RotatePlaceTest(currentDirTest, false, fakePlayer.rotation)
281+
else false
282+
} else true
283+
}
286284

287285
if (!placeConfig.axisRotate) {
288286
fakePlayer.rotation = checkedHit.targetRotation
289-
if (testPlaceState(context) != PlaceTestResult.Success) return false
290-
rot = fakePlayer.rotation
291-
return true
287+
return RotatePlaceTest(testPlaceState(context), currentDirIsValid, fakePlayer.rotation)
292288
}
293289

294290
fakePlayer.rotation = player.rotation
295-
if (testPlaceState(context) == PlaceTestResult.Success) {
296-
rot = fakePlayer.rotation
297-
return true
291+
testPlaceState(context).let { playerRotTest ->
292+
if (playerRotTest.testResult == PlaceTestResult.Success)
293+
return RotatePlaceTest(playerRotTest, currentDirIsValid, fakePlayer.rotation)
298294
}
299295

300296
PlaceDirection.entries.asReversed().forEachIndexed direction@{ index, direction ->
301297
fakePlayer.rotation = direction.rotation
302-
when (testPlaceState(context)) {
298+
val axisRotateTest = testPlaceState(context)
299+
when (axisRotateTest.testResult) {
303300
PlaceTestResult.BlockedByEntity -> return@direction
304301

305302
PlaceTestResult.NoIntegrity -> {
306303
if (index != PlaceDirection.entries.lastIndex) return@direction
307-
return false
304+
return RotatePlaceTest(axisRotateTest, currentDirIsValid, fakePlayer.rotation)
308305
}
309306

310-
else -> {
311-
rot = fakePlayer.rotation
312-
return true
313-
}
307+
else -> return RotatePlaceTest(axisRotateTest, currentDirIsValid, fakePlayer.rotation)
314308
}
315309
}
316310

317-
return true
311+
return null
318312
}
319313

320-
private fun SafeContext.testPlaceState(context: ItemPlacementContext): PlaceTestResult {
321-
resultState = blockItem.getPlacementState(context) ?: run {
314+
private fun SafeContext.testPlaceState(context: ItemPlacementContext): PlaceTest {
315+
val resultState = blockItem.getPlacementState(context) ?: run {
322316
result(PlaceResult.BlockedByEntity(pos))
323-
return PlaceTestResult.BlockedByEntity
317+
return PlaceTest(state, PlaceTestResult.BlockedByEntity)
324318
}
325319

326320
return if (!targetState.matches(resultState, pos, preProcessing.ignore)) {
327321
result(PlaceResult.NoIntegrity(pos, resultState, context, (targetState as? TargetState.State)?.blockState))
328-
PlaceTestResult.NoIntegrity
329-
} else PlaceTestResult.Success
322+
PlaceTest(resultState, PlaceTestResult.NoIntegrity)
323+
} else PlaceTest(resultState, PlaceTestResult.Success)
330324
}
331325

326+
private data class RotatePlaceTest(val placeTest: PlaceTest, val currentDirIsValid: Boolean, val rotation: Rotation) {
327+
val isValid = placeTest.testResult == PlaceTestResult.Success
328+
}
329+
private data class PlaceTest(val resultState: BlockState, val testResult: PlaceTestResult)
332330
private enum class PlaceTestResult {
333331
Success,
334332
BlockedByEntity,

src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,21 @@ sealed class TargetState(val type: Type) : StateMatcher {
7878
override fun isEmpty() = true
7979
}
8080

81-
data object Solid : TargetState(Type.Solid) {
81+
data class Solid(val replace: Set<net.minecraft.block.Block>) : TargetState(Type.Solid) {
8282
override fun toString() = "Solid"
8383

8484
context(safeContext: SafeContext)
8585
override fun matches(
8686
state: BlockState,
8787
pos: BlockPos,
8888
ignoredProperties: Collection<Property<*>>
89-
) = with(safeContext) { state.isSolidBlock(world, pos) }
89+
) = with(safeContext) { state.isSolidBlock(world, pos) && state.block !in replace }
9090

9191
context(automatedSafeContext: AutomatedSafeContext)
9292
override fun getStack(pos: BlockPos) =
9393
with(automatedSafeContext) {
9494
findDisposable()?.stacks?.firstOrNull {
95-
it.item.block in inventoryConfig.disposables
95+
it.item.block in inventoryConfig.disposables && it.item.block !in replace
9696
} ?: ItemStack(Items.NETHERRACK)
9797
}
9898

src/main/kotlin/com/lambda/module/modules/player/HighwayTools.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ object HighwayTools : Module(
8181
private val wallMaterial by setting("Wall Material", Blocks.NETHERRACK, "Material to build the walls with") { rightWall == Material.Block || leftWall == Material.Block }.group(Group.Structure)
8282
private val ceiling by setting("Ceiling", Material.None, "Material for the ceiling").group(Group.Structure)
8383
private val ceilingMaterial by setting("Ceiling Material", Blocks.OBSIDIAN, "Material to build the ceiling with") { ceiling == Material.Block }.group(Group.Structure)
84+
private val replaceableSolids by setting("Replaceable Solids", setOf(Blocks.MAGMA_BLOCK, Blocks.SOUL_SAND)).group(Group.Structure)
8485
private val distance by setting("Distance", -1, -1..1000000, 1, "Distance to build the highway/tunnel (negative for infinite)").group(Group.Structure)
8586
private val sliceSize by setting("Slice Size", 3, 1..5, 1, "Number of slices to build at once").group(Group.Structure)
8687

@@ -265,11 +266,10 @@ object HighwayTools : Module(
265266
return transformed
266267
}
267268

268-
private fun target(target: Material, material: net.minecraft.block.Block): TargetState {
269-
return when (target) {
270-
Material.Solid -> TargetState.Solid
269+
private fun target(target: Material, material: net.minecraft.block.Block) =
270+
when (target) {
271+
Material.Solid -> TargetState.Solid(replaceableSolids)
271272
Material.Block -> TargetState.Block(material)
272273
else -> throw IllegalStateException("Invalid material")
273274
}
274-
}
275275
}

src/main/kotlin/com/lambda/module/modules/player/Nuker.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
package com.lambda.module.modules.player
1919

20-
import com.lambda.context.AutomationConfig
2120
import com.lambda.interaction.BaritoneManager
2221
import com.lambda.interaction.construction.blueprint.TickingBlueprint.Companion.tickingBlueprint
2322
import com.lambda.interaction.construction.verify.TargetState
@@ -27,7 +26,7 @@ import com.lambda.task.RootTask.run
2726
import com.lambda.task.Task
2827
import com.lambda.task.tasks.BuildTask.Companion.build
2928
import com.lambda.util.BlockUtils.blockPos
30-
import com.lambda.util.BlockUtils.blockState
29+
import net.minecraft.block.Blocks
3130
import net.minecraft.util.math.BlockPos
3231

3332
object Nuker : Module(
@@ -39,7 +38,6 @@ object Nuker : Module(
3938
private val width by setting("Width", 4, 1..8, 1)
4039
private val flatten by setting("Flatten", true)
4140
private val fillFluids by setting("Fill Fluids", false, "Removes liquids by filling them in before breaking")
42-
private val instantOnly by setting("Instant Only", false)
4341
private val fillFloor by setting("Fill Floor", false)
4442
private val baritoneSelection by setting("Baritone Selection", false, "Restricts nuker to your baritone selection")
4543

@@ -53,7 +51,6 @@ object Nuker : Module(
5351
.map { it.blockPos }
5452
.filter { !world.isAir(it) }
5553
.filter { !flatten || it.y >= player.blockPos.y }
56-
.filter { !instantOnly || blockState(it).getHardness(world, it) <= AutomationConfig.breakConfig.breakThreshold }
5754
.filter { pos ->
5855
if (!baritoneSelection) true
5956
else BaritoneManager.primary.selectionManager.selections.any {
@@ -69,7 +66,7 @@ object Nuker : Module(
6966
if (fillFloor) {
7067
val floor = BlockPos.iterateOutwards(player.blockPos.down(), width, 0, width)
7168
.map { it.blockPos }
72-
.associateWith { TargetState.Solid }
69+
.associateWith { TargetState.Solid(setOf(Blocks.MAGMA_BLOCK)) }
7370
return@tickingBlueprint selection + floor
7471
}
7572

src/main/kotlin/com/lambda/module/modules/player/Scaffold.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ object Scaffold : Module(
9292
val beneath = playerSupport.down(offset)
9393
runSafeAutomated {
9494
scaffoldPositions(beneath)
95-
.associateWith { TargetState.Solid }
95+
.associateWith { TargetState.Solid(emptySet()) }
9696
.toBlueprint()
9797
.simulate()
9898
.filterIsInstance<PlaceResult.Place>()

0 commit comments

Comments
 (0)