Skip to content

Commit ff6b87b

Browse files
committed
better avoidLiquids logic
1 parent bb99955 commit ff6b87b

File tree

3 files changed

+75
-16
lines changed

3 files changed

+75
-16
lines changed

common/src/main/kotlin/com/lambda/interaction/construction/result/BreakResult.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,11 @@ sealed class BreakResult : BuildResult() {
140140
/**
141141
* The block is blocked by another liquid block that first has to be submerged.
142142
*/
143-
data class BlockedByLiquid(
143+
data class BlockedByFluid(
144144
override val blockPos: BlockPos,
145145
val blockState: BlockState,
146146
) : Drawable, BreakResult() {
147-
override val rank = Rank.BREAK_IS_BLOCKED_BY_LIQUID
147+
override val rank = Rank.BREAK_IS_BLOCKED_BY_FLUID
148148
private val color = Color(50, 12, 112, 100)
149149

150150
override fun SafeContext.buildRenderer() {

common/src/main/kotlin/com/lambda/interaction/construction/result/Rank.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum class Rank {
3838
BREAK_RESTRICTED,
3939
PLACE_NO_INTEGRITY,
4040
BREAK_SUBMERGE,
41-
BREAK_IS_BLOCKED_BY_LIQUID,
41+
BREAK_IS_BLOCKED_BY_FLUID,
4242
UNBREAKABLE,
4343
BREAK_NO_PERMISSION,
4444
PLACE_SCAFFOLD_EXCEEDED,

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

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,16 @@ import com.lambda.util.player.copyPlayer
6868
import com.lambda.util.player.gamemode
6969
import com.lambda.util.world.raycast.RayCastUtils.blockResult
7070
import net.minecraft.block.BlockState
71+
import net.minecraft.block.FallingBlock
7172
import net.minecraft.block.OperatorBlock
7273
import net.minecraft.block.SlabBlock
74+
import net.minecraft.block.Waterloggable
7375
import net.minecraft.block.enums.SlabType
7476
import net.minecraft.block.pattern.CachedBlockPosition
7577
import net.minecraft.enchantment.Enchantments
78+
import net.minecraft.fluid.FlowableFluid
79+
import net.minecraft.fluid.LavaFluid
80+
import net.minecraft.fluid.WaterFluid
7681
import net.minecraft.item.BlockItem
7782
import net.minecraft.item.Item
7883
import net.minecraft.item.ItemPlacementContext
@@ -601,22 +606,76 @@ object BuildSimulator {
601606
return acc
602607
}
603608

604-
val adjacentLiquids = Direction.entries.filter {
605-
it != Direction.DOWN && !blockState(pos.offset(it)).fluidState.isEmpty
606-
}.map { pos.offset(it) }
609+
if (breaking.avoidLiquids) {
610+
val affectedBlocks = hashSetOf(pos)
611+
val checkQueue = hashSetOf(pos)
607612

608-
/* block has liquids next to it that will leak when broken */
609-
if (adjacentLiquids.isNotEmpty() && breaking.avoidLiquids) {
610-
acc.add(BreakResult.BlockedByLiquid(pos, state))
611-
adjacentLiquids.forEach { liquidPos ->
612-
val submerge = if (blockState(liquidPos).isReplaceable) {
613-
checkPlaceResults(liquidPos, eye, preProcessing, TargetState.Solid, build.placing, interactionConfig, rotation, inventory)
614-
} else {
615-
checkBreakResults(liquidPos, eye, preProcessing, breaking, interactionConfig, rotation, inventory, build)
613+
while (checkQueue.isNotEmpty()) {
614+
val checkPos = checkQueue.first()
615+
checkQueue.remove(checkPos)
616+
for (offset in Direction.entries) {
617+
val adjacentPos = checkPos.offset(offset)
618+
619+
if (blockState(adjacentPos).block !is FallingBlock) continue
620+
if (adjacentPos in affectedBlocks) continue
621+
622+
if (offset == Direction.UP || FallingBlock.canFallThrough(blockState(adjacentPos.down()))) {
623+
checkQueue.add(adjacentPos)
624+
affectedBlocks.add(adjacentPos)
625+
}
616626
}
617-
acc.addAll(submerge)
618627
}
619-
return acc
628+
629+
val affectedFluids = affectedBlocks.fold(hashMapOf<BlockPos, BlockState>()) { accumulator, affectedPos ->
630+
Direction.entries.forEach { offset ->
631+
if (offset == Direction.DOWN) return@forEach
632+
633+
val offsetPos = affectedPos.offset(offset)
634+
val offsetState = blockState(offsetPos)
635+
val fluidState = offsetState.fluidState
636+
val fluid = fluidState.fluid
637+
638+
if (fluidState.isEmpty || fluid !is FlowableFluid) return@forEach
639+
640+
if (offset == Direction.UP) {
641+
accumulator.put(offsetPos, offsetState)
642+
return@fold accumulator
643+
}
644+
645+
if (offsetState.block is Waterloggable && !fluidState.isEmpty) {
646+
accumulator.put(offsetPos, offsetState)
647+
return@fold accumulator
648+
}
649+
650+
val levelDecreasePerBlock =
651+
when (fluid) {
652+
is WaterFluid -> fluid.getLevelDecreasePerBlock(world)
653+
is LavaFluid -> fluid.getLevelDecreasePerBlock(world)
654+
else -> 0
655+
}
656+
657+
if (fluidState.level - levelDecreasePerBlock > 0) {
658+
accumulator.put(offsetPos, offsetState)
659+
return@fold accumulator
660+
}
661+
}
662+
663+
return@fold accumulator
664+
}
665+
666+
/* block has liquids next to it that will leak when broken */
667+
if (affectedFluids.isNotEmpty()) {
668+
acc.add(BreakResult.BlockedByFluid(pos, state))
669+
affectedFluids.entries.forEach { fluid ->
670+
val submerge = if (fluid.value.isReplaceable) {
671+
checkPlaceResults(fluid.key, eye, preProcessing, TargetState.Solid, build.placing, interactionConfig, rotation, inventory)
672+
} else {
673+
checkBreakResults(fluid.key, eye, preProcessing, breaking, interactionConfig, rotation, inventory, build)
674+
}
675+
acc.addAll(submerge)
676+
}
677+
return acc
678+
}
620679
}
621680

622681
val currentRotation = RotationManager.activeRotation

0 commit comments

Comments
 (0)