diff --git a/server/src/main/java/com/soulfiremc/server/pathfinding/execution/BlockBreakAction.java b/server/src/main/java/com/soulfiremc/server/pathfinding/execution/BlockBreakAction.java index 5d7c52334..87a7e35de 100644 --- a/server/src/main/java/com/soulfiremc/server/pathfinding/execution/BlockBreakAction.java +++ b/server/src/main/java/com/soulfiremc/server/pathfinding/execution/BlockBreakAction.java @@ -49,8 +49,9 @@ public BlockBreakAction(MovementMiningCost movementMiningCost) { @Override public boolean isCompleted(BotConnection connection) { var level = connection.dataManager().currentLevel(); + var blockType = level.getBlockState(blockPosition).blockType(); - return SFBlockHelpers.isEmptyBlock(level.getBlockState(blockPosition).blockType()); + return SFBlockHelpers.isEmptyBlock(blockType); } @Override diff --git a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/DownMovement.java b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/DownMovement.java index 66670fd98..fc9e39d0a 100644 --- a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/DownMovement.java +++ b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/DownMovement.java @@ -58,43 +58,39 @@ public static void registerDownMovements( callback.accept(registerDownMovement(blockSubscribers, new DownMovement())); } - public static DownMovement registerDownMovement( + private static DownMovement registerDownMovement( BiConsumer> blockSubscribers, DownMovement movement) { { for (var safetyBlock : movement.listSafetyCheckBlocks()) { blockSubscribers - .accept(safetyBlock, new DownMovementBlockSubscription(DownMovementBlockSubscription.SubscriptionType.DOWN_SAFETY_CHECK)); + .accept(safetyBlock, new DownSafetyCheckSubscription()); } } { for (var obstructingBlock : movement.listObstructFallCheckBlocks()) { blockSubscribers - .accept(obstructingBlock, new DownMovementBlockSubscription(DownMovementBlockSubscription.SubscriptionType.MOVEMENT_OBSTRUCTING_FALL_CHECK)); + .accept(obstructingBlock, new ObstructingFallCheckSubscription()); } } { var freeBlock = movement.blockToBreak(); blockSubscribers - .accept(freeBlock.key(), new DownMovementBlockSubscription(DownMovementBlockSubscription.SubscriptionType.MOVEMENT_FREE, 0, freeBlock.value())); + .accept(freeBlock.key(), new MovementFreeSubscription(freeBlock.value())); } { var safeBlocks = movement.listCheckSafeMineBlocks(); - for (var i = 0; i < safeBlocks.length; i++) { - var savedBlock = safeBlocks[i]; + for (var savedBlock : safeBlocks) { if (savedBlock == null) { continue; } for (var block : savedBlock) { blockSubscribers - .accept(block.position(), new DownMovementBlockSubscription( - DownMovementBlockSubscription.SubscriptionType.MOVEMENT_BREAK_SAFETY_CHECK, - i, - block.type())); + .accept(block.position(), new MovementBreakSafetyCheckSubscription(block.type())); } } } @@ -197,107 +193,94 @@ public DownMovement clone() { } } - record DownMovementBlockSubscription( - SubscriptionType type, - int blockArrayIndex, - BlockFace blockBreakSideHint, - BlockSafetyData.BlockSafetyType safetyType) implements MinecraftGraph.MovementSubscription { - DownMovementBlockSubscription(SubscriptionType type) { - this(type, -1, null, null); + interface DownMovementSubscription extends MinecraftGraph.MovementSubscription { + @Override + default DownMovement castAction(GraphAction action) { + return (DownMovement) action; } + } - DownMovementBlockSubscription(SubscriptionType type, int blockArrayIndex, BlockFace blockBreakSideHint) { - this(type, blockArrayIndex, blockBreakSideHint, null); - } + record MovementFreeSubscription(BlockFace blockBreakSideHint) implements DownMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, DownMovement downMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + if (graph.disallowedToBreakBlock(absoluteKey) + || graph.disallowedToBreakBlockType(blockState.blockType())) { + // No way to break this block + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - DownMovementBlockSubscription( - SubscriptionType subscriptionType, - int i, - BlockSafetyData.BlockSafetyType type) { - this(subscriptionType, i, null, type); + var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); + // We can mine this block, lets add costs and continue + downMovement.breakCost = new MovementMiningCost( + absoluteKey, + cacheableMiningCost.miningCost(), + cacheableMiningCost.willDropUsableBlockItem(), + blockBreakSideHint); + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record DownSafetyCheckSubscription() implements DownMovementSubscription { @Override public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, DownMovement downMovement, LazyBoolean isFree, BlockState blockState, SFVec3i absoluteKey) { - return switch (type) { - case MOVEMENT_FREE -> { - if (graph.disallowedToBreakBlock(absoluteKey) - || graph.disallowedToBreakBlockType(blockState.blockType())) { - // No way to break this block - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); - // We can mine this block, lets add costs and continue - downMovement.breakCost = new MovementMiningCost( - absoluteKey, - cacheableMiningCost.miningCost(), - cacheableMiningCost.willDropUsableBlockItem(), - blockBreakSideHint); - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case DOWN_SAFETY_CHECK -> { - var yLevel = key.y; + var yLevel = key.y; - if (yLevel < downMovement.closestBlockToFallOn) { - // We already found a block to fall on, above this one - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + if (yLevel < downMovement.closestBlockToFallOn) { + // We already found a block to fall on, above this one + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { - // We found a block to fall on - downMovement.closestBlockToFallOn = yLevel; - } + if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { + // We found a block to fall on + downMovement.closestBlockToFallOn = yLevel; + } - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_BREAK_SAFETY_CHECK -> { - var unsafe = safetyType.isUnsafeBlock(blockState); + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + } + + record MovementBreakSafetyCheckSubscription(BlockSafetyData.BlockSafetyType safetyType) implements DownMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, DownMovement downMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + var unsafe = safetyType.isUnsafeBlock(blockState); - if (unsafe) { - // We know already WE MUST dig the block below for this action - // So if one block around the block below is unsafe, we can't do this action - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } + if (unsafe) { + // We know already WE MUST dig the block below for this action + // So if one block around the block below is unsafe, we can't do this action + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - // All good, we can continue - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_OBSTRUCTING_FALL_CHECK -> { - var yLevel = key.y; - - if (yLevel < downMovement.closestObstructingBlock) { - // We already found a higher obstructing block - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - if (yLevel < downMovement.closestBlockToFallOn) { - // We only search blocks above the closest block to fall on - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - if (isFree.get()) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - // We found a block that obstructs our fall - downMovement.closestObstructingBlock = yLevel; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - }; + // All good, we can continue + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record ObstructingFallCheckSubscription() implements DownMovementSubscription { @Override - public DownMovement castAction(GraphAction action) { - return (DownMovement) action; - } + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, DownMovement downMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + var yLevel = key.y; + + if (yLevel < downMovement.closestObstructingBlock) { + // We already found a higher obstructing block + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + + if (yLevel < downMovement.closestBlockToFallOn) { + // We only search blocks above the closest block to fall on + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + + if (isFree.get()) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - enum SubscriptionType { - MOVEMENT_FREE, - DOWN_SAFETY_CHECK, - MOVEMENT_BREAK_SAFETY_CHECK, - MOVEMENT_OBSTRUCTING_FALL_CHECK + // We found a block that obstructs our fall + downMovement.closestObstructingBlock = yLevel; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } } } diff --git a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/ParkourMovement.java b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/ParkourMovement.java index 8324117fe..eb9d182ab 100644 --- a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/ParkourMovement.java +++ b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/ParkourMovement.java @@ -25,9 +25,7 @@ import com.soulfiremc.server.pathfinding.graph.BlockFace; import com.soulfiremc.server.pathfinding.graph.GraphInstructions; import com.soulfiremc.server.pathfinding.graph.MinecraftGraph; -import com.soulfiremc.server.pathfinding.graph.actions.movement.BlockSafetyData; import com.soulfiremc.server.pathfinding.graph.actions.movement.ParkourDirection; -import com.soulfiremc.server.protocol.bot.BotActionManager; import com.soulfiremc.server.util.SFBlockHelpers; import com.soulfiremc.server.util.structs.LazyBoolean; import it.unimi.dsi.fastutil.Pair; @@ -62,21 +60,20 @@ private static ParkourMovement registerParkourMovement( BiConsumer> blockSubscribers, ParkourMovement movement) { { - var blockId = 0; for (var freeBlock : movement.listRequiredFreeBlocks()) { blockSubscribers - .accept(freeBlock.key(), new ParkourMovementBlockSubscription(ParkourMovementBlockSubscription.SubscriptionType.MOVEMENT_FREE, blockId++, freeBlock.value())); + .accept(freeBlock.key(), new MovementFreeSubscription()); } } { blockSubscribers - .accept(movement.requiredUnsafeBlock(), new ParkourMovementBlockSubscription(ParkourMovementBlockSubscription.SubscriptionType.PARKOUR_UNSAFE_TO_STAND_ON)); + .accept(movement.requiredUnsafeBlock(), new ParkourUnsafeToStandOnSubscription()); } { blockSubscribers - .accept(movement.requiredSolidBlock(), new ParkourMovementBlockSubscription(ParkourMovementBlockSubscription.SubscriptionType.MOVEMENT_SOLID)); + .accept(movement.requiredSolidBlock(), new MovementSolidSubscription()); } return movement; @@ -140,62 +137,50 @@ public ParkourMovement clone() { } } - record ParkourMovementBlockSubscription( - SubscriptionType type, - int blockArrayIndex, - BlockFace blockBreakSideHint, - BotActionManager.BlockPlaceAgainstData blockToPlaceAgainst, - BlockSafetyData.BlockSafetyType safetyType) implements MinecraftGraph.MovementSubscription { - ParkourMovementBlockSubscription(SubscriptionType type) { - this(type, -1, null, null, null); + interface ParkourMovementSubscription extends MinecraftGraph.MovementSubscription { + @Override + default ParkourMovement castAction(GraphAction action) { + return (ParkourMovement) action; } + } + + record MovementFreeSubscription() implements ParkourMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, ParkourMovement parkourMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + if (isFree.get()) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - ParkourMovementBlockSubscription(SubscriptionType type, int blockArrayIndex, BlockFace blockBreakSideHint) { - this(type, blockArrayIndex, blockBreakSideHint, null, null); + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; } + } + record ParkourUnsafeToStandOnSubscription() implements ParkourMovementSubscription { @Override public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, ParkourMovement parkourMovement, LazyBoolean isFree, BlockState blockState, SFVec3i absoluteKey) { + // We only want to jump over dangerous blocks/gaps + // So either a non-full-block like water or lava or magma + // since it hurts to stand on. + if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - return switch (type) { - case MOVEMENT_FREE -> { - if (isFree.get()) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - case PARKOUR_UNSAFE_TO_STAND_ON -> { - // We only want to jump over dangerous blocks/gaps - // So either a non-full-block like water or lava or magma - // since it hurts to stand on. - if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_SOLID -> { - // Block is safe to walk on, no need to check for more - if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - }; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record MovementSolidSubscription() implements ParkourMovementSubscription { @Override - public ParkourMovement castAction(GraphAction action) { - return (ParkourMovement) action; - } + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, ParkourMovement parkourMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + // Block is safe to walk on, no need to check for more + if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - enum SubscriptionType { - MOVEMENT_FREE, - PARKOUR_UNSAFE_TO_STAND_ON, - MOVEMENT_SOLID + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; } } } diff --git a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/SimpleMovement.java b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/SimpleMovement.java index ac5446df9..3d3fd0cb4 100644 --- a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/SimpleMovement.java +++ b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/SimpleMovement.java @@ -122,7 +122,7 @@ private static SimpleMovement registerMovement( var blockId = 0; for (var freeBlock : movement.requiredFreeBlocks) { blockSubscribers - .accept(freeBlock.key(), new SimpleMovementBlockSubscription(SimpleMovementBlockSubscription.SubscriptionType.MOVEMENT_FREE, blockId++, freeBlock.value())); + .accept(freeBlock.key(), new MovementFreeSubscription(blockId++, freeBlock.value())); } } @@ -136,32 +136,27 @@ private static SimpleMovement registerMovement( for (var block : savedBlock) { blockSubscribers - .accept(block.position(), new SimpleMovementBlockSubscription( - SimpleMovementBlockSubscription.SubscriptionType.MOVEMENT_BREAK_SAFETY_CHECK, - i, - block.type())); + .accept(block.position(), new MovementBreakSafetyCheckSubscription(i, block.type())); } } } { blockSubscribers - .accept(movement.requiredSolidBlock(), new SimpleMovementBlockSubscription(SimpleMovementBlockSubscription.SubscriptionType.MOVEMENT_SOLID)); + .accept(movement.requiredSolidBlock(), new MovementSolidSubscription()); } { for (var diagonalCollisionBlock : movement.listDiagonalCollisionBlocks()) { blockSubscribers - .accept(diagonalCollisionBlock.key(), new SimpleMovementBlockSubscription( - SimpleMovementBlockSubscription.SubscriptionType.MOVEMENT_DIAGONAL_COLLISION, diagonalCollisionBlock.value())); + .accept(diagonalCollisionBlock.key(), new MovementDiagonalCollisionSubscription(diagonalCollisionBlock.value())); } } { for (var againstBlock : movement.possibleBlocksToPlaceAgainst()) { blockSubscribers - .accept(againstBlock.againstPos(), new SimpleMovementBlockSubscription( - SimpleMovementBlockSubscription.SubscriptionType.MOVEMENT_AGAINST_PLACE_SOLID, againstBlock)); + .accept(againstBlock.againstPos(), new MovementAgainstPlaceSolidSubscription(againstBlock)); } } @@ -434,169 +429,148 @@ public SimpleMovement clone() { } } - record SimpleMovementBlockSubscription( - SubscriptionType type, - int blockArrayIndex, - BlockFace blockBreakSideHint, - BotActionManager.BlockPlaceAgainstData blockToPlaceAgainst, - BlockSafetyData.BlockSafetyType safetyType, - MovementSide side) implements MinecraftGraph.MovementSubscription { - SimpleMovementBlockSubscription(SubscriptionType type) { - this(type, -1, null, null, null, null); + interface SimpleMovementSubscription extends MinecraftGraph.MovementSubscription { + @Override + default SimpleMovement castAction(GraphAction action) { + return (SimpleMovement) action; } + } - SimpleMovementBlockSubscription(SubscriptionType type, MovementSide side) { - this(type, -1, null, null, null, side); - } + record MovementFreeSubscription(int blockArrayIndex, BlockFace blockBreakSideHint) implements SimpleMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, SimpleMovement simpleMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + if (isFree.get()) { + if (simpleMovement.allowBlockActions) { + simpleMovement.noNeedToBreak[blockArrayIndex] = true; + } - SimpleMovementBlockSubscription(SubscriptionType type, int blockArrayIndex, BlockFace blockBreakSideHint) { - this(type, blockArrayIndex, blockBreakSideHint, null, null, null); - } + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - SimpleMovementBlockSubscription( - SubscriptionType type, - BotActionManager.BlockPlaceAgainstData blockToPlaceAgainst) { - this(type, -1, null, blockToPlaceAgainst, null, null); - } + // Search for a way to break this block + if (graph.disallowedToBreakBlock(absoluteKey) + || !simpleMovement.allowBlockActions + || graph.disallowedToBreakBlockType(blockState.blockType()) + // Check if we previously found out this block is unsafe to break + || simpleMovement.unsafeToBreak[blockArrayIndex]) { + // No way to break this block + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - SimpleMovementBlockSubscription( - SubscriptionType subscriptionType, - int i, - BlockSafetyData.BlockSafetyType type) { - this(subscriptionType, i, null, null, type, null); + var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); + // We can mine this block, lets add costs and continue + simpleMovement.blockBreakCosts[blockArrayIndex] = + new MovementMiningCost( + absoluteKey, + cacheableMiningCost.miningCost(), + cacheableMiningCost.willDropUsableBlockItem(), + blockBreakSideHint); + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record MovementBreakSafetyCheckSubscription(int blockArrayIndex, BlockSafetyData.BlockSafetyType safetyType) implements SimpleMovementSubscription { @Override public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, SimpleMovement simpleMovement, LazyBoolean isFree, BlockState blockState, SFVec3i absoluteKey) { - return switch (type) { - case MOVEMENT_FREE -> { - if (isFree.get()) { - if (simpleMovement.allowBlockActions) { - simpleMovement.noNeedToBreak[blockArrayIndex] = true; - } - - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - // Search for a way to break this block - if (graph.disallowedToBreakBlock(absoluteKey) - || !simpleMovement.allowBlockActions - || graph.disallowedToBreakBlockType(blockState.blockType()) - // Check if we previously found out this block is unsafe to break - || simpleMovement.unsafeToBreak[blockArrayIndex]) { - // No way to break this block - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); - // We can mine this block, lets add costs and continue - simpleMovement.blockBreakCosts[blockArrayIndex] = - new MovementMiningCost( - absoluteKey, - cacheableMiningCost.miningCost(), - cacheableMiningCost.willDropUsableBlockItem(), - blockBreakSideHint); - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_BREAK_SAFETY_CHECK -> { - // There is no need to break this block, so there is no need for safety checks - if (simpleMovement.noNeedToBreak[blockArrayIndex]) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + // There is no need to break this block, so there is no need for safety checks + if (simpleMovement.noNeedToBreak[blockArrayIndex]) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - // The block was already marked as unsafe - if (simpleMovement.unsafeToBreak[blockArrayIndex]) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + // The block was already marked as unsafe + if (simpleMovement.unsafeToBreak[blockArrayIndex]) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - var unsafe = safetyType.isUnsafeBlock(blockState); + var unsafe = safetyType.isUnsafeBlock(blockState); - if (!unsafe) { - // All good, we can continue - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + if (!unsafe) { + // All good, we can continue + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - var currentValue = simpleMovement.blockBreakCosts[blockArrayIndex]; + var currentValue = simpleMovement.blockBreakCosts[blockArrayIndex]; - if (currentValue != null) { - // We learned that this block needs to be broken, so we need to set it as impossible - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } + if (currentValue != null) { + // We learned that this block needs to be broken, so we need to set it as impossible + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - // Store for a later time that this is unsafe, - // so if we check this block, - // we know it's unsafe - simpleMovement.unsafeToBreak[blockArrayIndex] = true; + // Store for a later time that this is unsafe, + // so if we check this block, + // we know it's unsafe + simpleMovement.unsafeToBreak[blockArrayIndex] = true; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_SOLID -> { - // Block is safe to walk on, no need to check for more - if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - if (graph.disallowedToPlaceBlock(absoluteKey) - || !simpleMovement.allowBlockActions - || !blockState.blockType().replaceable()) { - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - // We can place a block here, but we need to find a block to place against - simpleMovement.requiresAgainstBlock = true; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_AGAINST_PLACE_SOLID -> { - // We already found one, no need to check for more - if (simpleMovement.blockPlaceAgainstData != null) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - // This block should not be placed against - if (!blockState.blockCollisionShapeGroup().isFullBlock()) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - // Fixup the position to be the block we are placing against instead of relative - simpleMovement.blockPlaceAgainstData = new BotActionManager.BlockPlaceAgainstData( - absoluteKey, blockToPlaceAgainst.blockFace()); - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_DIAGONAL_COLLISION -> { - if (SFBlockHelpers.isHurtOnTouchSide(blockState.blockType())) { - // Since this is a corner, we can also avoid touching blocks that hurt us, e.g., cacti - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } else if (blockState.blockCollisionShapeGroup().hasCollisions()) { - var blockedSide = simpleMovement.blockedSide; - if (blockedSide == null) { - simpleMovement.blockedSide = side; - simpleMovement.cost = simpleMovement.cost + Costs.CORNER_SLIDE; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } else if (blockedSide == side) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } else { - // Diagonal path is blocked on both sides - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - } - - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - }; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + } + + record MovementSolidSubscription() implements SimpleMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, SimpleMovement simpleMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + // Block is safe to walk on, no need to check for more + if (SFBlockHelpers.isSafeBlockToStandOn(blockState)) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + + if (graph.disallowedToPlaceBlock(absoluteKey) + || !simpleMovement.allowBlockActions + || !blockState.blockType().replaceable()) { + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } + + // We can place a block here, but we need to find a block to place against + simpleMovement.requiresAgainstBlock = true; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record MovementDiagonalCollisionSubscription(MovementSide side) implements SimpleMovementSubscription { @Override - public SimpleMovement castAction(GraphAction action) { - return (SimpleMovement) action; + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, SimpleMovement simpleMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + if (SFBlockHelpers.isHurtOnTouchSide(blockState.blockType())) { + // Since this is a corner, we can also avoid touching blocks that hurt us, e.g., cacti + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } else if (blockState.blockCollisionShapeGroup().hasCollisions()) { + var blockedSide = simpleMovement.blockedSide; + if (blockedSide == null) { + simpleMovement.blockedSide = side; + simpleMovement.cost = simpleMovement.cost + Costs.CORNER_SLIDE; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } else if (blockedSide == side) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } else { + // Diagonal path is blocked on both sides + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } + } + + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + + record MovementAgainstPlaceSolidSubscription(BotActionManager.BlockPlaceAgainstData blockToPlaceAgainst) implements SimpleMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, SimpleMovement simpleMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + // We already found one, no need to check for more + if (simpleMovement.blockPlaceAgainstData != null) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + + // This block should not be placed against + if (!blockState.blockCollisionShapeGroup().isFullBlock()) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - enum SubscriptionType { - MOVEMENT_FREE, - MOVEMENT_BREAK_SAFETY_CHECK, - MOVEMENT_SOLID, - MOVEMENT_DIAGONAL_COLLISION, - MOVEMENT_AGAINST_PLACE_SOLID + // Fixup the position to be the block we are placing against instead of relative + simpleMovement.blockPlaceAgainstData = new BotActionManager.BlockPlaceAgainstData( + absoluteKey, blockToPlaceAgainst.blockFace()); + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } } } diff --git a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/UpMovement.java b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/UpMovement.java index 40425c257..4ceed68bb 100644 --- a/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/UpMovement.java +++ b/server/src/main/java/com/soulfiremc/server/pathfinding/graph/actions/UpMovement.java @@ -75,13 +75,13 @@ private static UpMovement registerUpMovement( var blockId = 0; for (var freeBlock : movement.requiredFreeBlocks) { blockSubscribers - .accept(freeBlock.key(), new UpMovementBlockSubscription(UpMovementBlockSubscription.SubscriptionType.MOVEMENT_FREE, blockId++, freeBlock.value())); + .accept(freeBlock.key(), new MovementFreeSubscription(blockId++, freeBlock.value())); } } { blockSubscribers - .accept(movement.blockPlacePosition(), new UpMovementBlockSubscription(UpMovementBlockSubscription.SubscriptionType.MOVEMENT_SOLID)); + .accept(movement.blockPlacePosition(), new MovementSolidSubscription()); } { @@ -94,10 +94,7 @@ private static UpMovement registerUpMovement( for (var block : savedBlock) { blockSubscribers - .accept(block.position(), new UpMovementBlockSubscription( - UpMovementBlockSubscription.SubscriptionType.MOVEMENT_BREAK_SAFETY_CHECK, - i, - block.type())); + .accept(block.position(), new MovementBreakSafetyCheckSubscription(i, block.type())); } } } @@ -219,106 +216,89 @@ public UpMovement clone() { } } - record UpMovementBlockSubscription( - SubscriptionType type, - int blockArrayIndex, - BlockFace blockBreakSideHint, - BlockSafetyData.BlockSafetyType safetyType) implements MinecraftGraph.MovementSubscription { - UpMovementBlockSubscription(SubscriptionType type) { - this(type, -1, null, null); + interface UpMovementSubscription extends MinecraftGraph.MovementSubscription { + @Override + default UpMovement castAction(GraphAction action) { + return (UpMovement) action; } + } - UpMovementBlockSubscription(SubscriptionType type, int blockArrayIndex, BlockFace blockBreakSideHint) { - this(type, blockArrayIndex, blockBreakSideHint, null); - } + record MovementFreeSubscription(int blockArrayIndex, BlockFace blockBreakSideHint) implements UpMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, UpMovement upMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + if (isFree.get()) { + upMovement.noNeedToBreak[blockArrayIndex] = true; + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - UpMovementBlockSubscription( - SubscriptionType subscriptionType, - int i, - BlockSafetyData.BlockSafetyType type) { - this(subscriptionType, i, null, type); + // Search for a way to break this block + if (graph.disallowedToBreakBlock(absoluteKey) + || graph.disallowedToBreakBlockType(blockState.blockType()) + || upMovement.unsafeToBreak[blockArrayIndex]) { + // No way to break this block + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } + + var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); + // We can mine this block, lets add costs and continue + upMovement.blockBreakCosts[blockArrayIndex] = + new MovementMiningCost( + absoluteKey, + cacheableMiningCost.miningCost(), + cacheableMiningCost.willDropUsableBlockItem(), + blockBreakSideHint); + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } + } + record MovementSolidSubscription() implements UpMovementSubscription { @Override public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, UpMovement upMovement, LazyBoolean isFree, BlockState blockState, SFVec3i absoluteKey) { - return switch (type) { - case MOVEMENT_FREE -> { - if (isFree.get()) { - upMovement.noNeedToBreak[blockArrayIndex] = true; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - - // Search for a way to break this block - if (graph.disallowedToBreakBlock(absoluteKey) - || graph.disallowedToBreakBlockType(blockState.blockType()) - || upMovement.unsafeToBreak[blockArrayIndex]) { - // No way to break this block - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - var cacheableMiningCost = graph.inventory().getMiningCosts(graph.tagsState(), blockState); - // We can mine this block, lets add costs and continue - upMovement.blockBreakCosts[blockArrayIndex] = - new MovementMiningCost( - absoluteKey, - cacheableMiningCost.miningCost(), - cacheableMiningCost.willDropUsableBlockItem(), - blockBreakSideHint); - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_SOLID -> { - // Towering requires placing a block at old feet position - if (graph.disallowedToPlaceBlock(absoluteKey)) { - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } - - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - case MOVEMENT_BREAK_SAFETY_CHECK -> { - // There is no need to break this block, so there is no need for safety checks - if (upMovement.noNeedToBreak[blockArrayIndex]) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + // Towering requires placing a block at old feet position + if (graph.disallowedToPlaceBlock(absoluteKey)) { + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - // The block was already marked as unsafe - if (upMovement.unsafeToBreak[blockArrayIndex]) { - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } + } - var unsafe = safetyType.isUnsafeBlock(blockState); + record MovementBreakSafetyCheckSubscription(int blockArrayIndex, BlockSafetyData.BlockSafetyType safetyType) implements UpMovementSubscription { + @Override + public MinecraftGraph.SubscriptionSingleResult processBlock(MinecraftGraph graph, SFVec3i key, UpMovement upMovement, LazyBoolean isFree, + BlockState blockState, SFVec3i absoluteKey) { + // There is no need to break this block, so there is no need for safety checks + if (upMovement.noNeedToBreak[blockArrayIndex]) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - if (!unsafe) { - // All good, we can continue - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } + // The block was already marked as unsafe + if (upMovement.unsafeToBreak[blockArrayIndex]) { + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - var currentValue = upMovement.blockBreakCosts[blockArrayIndex]; + var unsafe = safetyType.isUnsafeBlock(blockState); - if (currentValue != null) { - // We learned that this block needs to be broken, so we need to set it as impossible - yield MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; - } + if (!unsafe) { + // All good, we can continue + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; + } - // Store for a later time that this is unsafe, - // so if we check this block, - // we know it's unsafe - upMovement.unsafeToBreak[blockArrayIndex] = true; + var currentValue = upMovement.blockBreakCosts[blockArrayIndex]; - yield MinecraftGraph.SubscriptionSingleResult.CONTINUE; - } - }; - } + if (currentValue != null) { + // We learned that this block needs to be broken, so we need to set it as impossible + return MinecraftGraph.SubscriptionSingleResult.IMPOSSIBLE; + } - @Override - public UpMovement castAction(GraphAction action) { - return (UpMovement) action; - } + // Store for a later time that this is unsafe, + // so if we check this block, + // we know it's unsafe + upMovement.unsafeToBreak[blockArrayIndex] = true; - enum SubscriptionType { - MOVEMENT_FREE, - MOVEMENT_SOLID, - MOVEMENT_BREAK_SAFETY_CHECK + return MinecraftGraph.SubscriptionSingleResult.CONTINUE; } } }