diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index c70d60dee..2a14e8dfb 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -398,6 +398,11 @@ public final class Settings { */ public final Setting containerMemory = new Setting<>(false); + /** + * Fill in blocks behind you + */ + public final Setting backfill = new Setting<>(false); + /** * Print all the debug messages to chat */ diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index f7a20b0f6..9d93f68f5 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -80,6 +80,7 @@ public class Baritone implements IBaritone { private CustomGoalProcess customGoalProcess; private BuilderProcess builderProcess; private ExploreProcess exploreProcess; + private BackfillProcess backfillProcess; private PathingControlManager pathingControlManager; @@ -120,6 +121,7 @@ public class Baritone implements IBaritone { getToBlockProcess = new GetToBlockProcess(this); builderProcess = new BuilderProcess(this); exploreProcess = new ExploreProcess(this); + backfillProcess = new BackfillProcess(this); } this.worldProvider = new WorldProvider(); diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index 120bc7489..ae8e5bfa5 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -130,13 +130,13 @@ public class InventoryBehavior extends Behavior { return false; } - public boolean selectThrowawayForLocation(int x, int y, int z) { + public boolean selectThrowawayForLocation(boolean select, int x, int y, int z) { IBlockState maybe = baritone.getBuilderProcess().placeAt(x, y, z); - if (maybe != null && throwaway(true, item -> item instanceof ItemBlock && ((ItemBlock) item).getBlock().equals(maybe.getBlock()))) { + if (maybe != null && throwaway(select, item -> item instanceof ItemBlock && ((ItemBlock) item).getBlock().equals(maybe.getBlock()))) { return true; // gotem } for (Item item : Baritone.settings().acceptableThrowawayItems.value) { - if (throwaway(true, item::equals)) { + if (throwaway(select, item::equals)) { return true; } } diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index 96b650e74..8c0ba2f87 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -270,4 +270,8 @@ public abstract class Movement implements IMovement, MovementHelper { } return toWalkIntoCached; } + + public BlockPos[] toBreakAll() { + return positionsToBreak; + } } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 12ab8e72f..a7247df33 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -478,8 +478,8 @@ public interface MovementHelper extends ActionCosts, Helper { for (int i = 0; i < 5; i++) { BlockPos against1 = placeAt.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]); if (MovementHelper.canPlaceAgainst(ctx, against1)) { - if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block - Helper.HELPER.logDebug("bb pls get me some blocks. dirt or cobble"); + if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(false, placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block + Helper.HELPER.logDebug("bb pls get me some blocks. dirt, netherrack, cobble"); state.setStatus(MovementStatus.UNREACHABLE); return PlaceResult.NO_OPTION; } @@ -505,10 +505,15 @@ public interface MovementHelper extends ActionCosts, Helper { EnumFacing side = ctx.objectMouseOver().sideHit; // only way for selectedBlock.equals(placeAt) to be true is if it's replacable if (selectedBlock.equals(placeAt) || (MovementHelper.canPlaceAgainst(ctx, selectedBlock) && selectedBlock.offset(side).equals(placeAt))) { + ((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ()); return PlaceResult.READY_TO_PLACE; } } - return found ? PlaceResult.ATTEMPTING : PlaceResult.NO_OPTION; + if (found) { + ((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ()); + return PlaceResult.ATTEMPTING; + } + return PlaceResult.NO_OPTION; } enum PlaceResult { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index cbe375dea..1d8493538 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -208,7 +208,7 @@ public class MovementPillar extends Movement { return state; } else { // Get ready to place a throwaway block - if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(src.x, src.y, src.z)) { + if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, src.x, src.y, src.z)) { return state.setStatus(MovementStatus.UNREACHABLE); } diff --git a/src/main/java/baritone/process/BackfillProcess.java b/src/main/java/baritone/process/BackfillProcess.java new file mode 100644 index 000000000..193204aea --- /dev/null +++ b/src/main/java/baritone/process/BackfillProcess.java @@ -0,0 +1,136 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.api.utils.input.Input; +import baritone.pathing.movement.Movement; +import baritone.pathing.movement.MovementHelper; +import baritone.pathing.movement.MovementState; +import baritone.pathing.path.PathExecutor; +import baritone.utils.BaritoneProcessHelper; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.EmptyChunk; + +import java.util.*; +import java.util.stream.Collectors; + +public class BackfillProcess extends BaritoneProcessHelper { + + public HashMap blocksToReplace = new HashMap<>(); + + public BackfillProcess(Baritone baritone) { + super(baritone); + } + + @Override + public boolean isActive() { + if (!Baritone.settings().backfill.value) { + return false; + } + if (Baritone.settings().allowParkour.value) { + logDirect("Backfill cannot be used with allowParkour true"); + Baritone.settings().backfill.value = false; + return false; + } + amIBreakingABlockHMMMMMMM(); + for (BlockPos pos : new ArrayList<>(blocksToReplace.keySet())) { + if (ctx.world().getChunk(pos) instanceof EmptyChunk) { + blocksToReplace.remove(pos); + } + } + baritone.getInputOverrideHandler().clearAllKeys(); + + return !toFillIn().isEmpty(); + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + if (!isSafeToCancel) { + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + baritone.getInputOverrideHandler().clearAllKeys(); + for (BlockPos toPlace : toFillIn()) { + MovementState fake = new MovementState(); + switch (MovementHelper.attemptToPlaceABlock(fake, baritone, toPlace, false)) { + case NO_OPTION: + continue; + case READY_TO_PLACE: + baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + case ATTEMPTING: + // patience + baritone.getLookBehavior().updateTarget(fake.getTarget().getRotation().get(), true); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } + } + return null; // cede to other process + } + + public void amIBreakingABlockHMMMMMMM() { + if (!ctx.getSelectedBlock().isPresent()) { + return; + } + blocksToReplace.put(ctx.getSelectedBlock().get(), ctx.world().getBlockState(ctx.getSelectedBlock().get())); + } + + public List toFillIn() { + return blocksToReplace + .keySet() + .stream() + .filter(pos -> ctx.world().getBlockState(pos).getBlock() == Blocks.AIR) + .filter(pos -> ctx.world().mayPlace(Blocks.DIRT, pos, false, EnumFacing.UP, null)) + .filter(pos -> !partOfCurrentMovement(pos)) + .sorted(Comparator.comparingDouble(ctx.player()::getDistanceSq).reversed()) + .collect(Collectors.toList()); + } + + private boolean partOfCurrentMovement(BlockPos pos) { + PathExecutor exec = baritone.getPathingBehavior().getCurrent(); + if (exec == null || exec.finished() || exec.failed()) { + return false; + } + Movement movement = (Movement) exec.getPath().movements().get(exec.getPosition()); + return Arrays.asList(movement.toBreakAll()).contains(pos); + } + + @Override + public void onLostControl() { + blocksToReplace = new HashMap<>(); + } + + @Override + public String displayName0() { + return "Backfill"; + } + + @Override + public boolean isTemporary() { + return true; + } + + @Override + public double priority() { + return 5; + } +} diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index f6a6954d2..46b69ec20 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -92,8 +92,8 @@ public class PathingControlManager implements IPathingControlManager { p.secretInternalSetGoal(null); return; } - if (inControlThisTick != inControlLastTick && command.commandType != PathingCommandType.REQUEST_PAUSE) { - // if control has changed, and the new process wants to do something + if (inControlThisTick != inControlLastTick && command.commandType != PathingCommandType.REQUEST_PAUSE && inControlLastTick != null && !inControlLastTick.isTemporary()) { + // if control has changed from a real process to another real process, and the new process wants to do something p.cancelSegmentIfSafe(); // get rid of the in progress stuff from the last process } @@ -199,10 +199,10 @@ public class PathingControlManager implements IPathingControlManager { PathingCommand exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel()); if (exec == null) { - if (proc.isActive()) { + /*if (proc.isActive()) { throw new IllegalStateException(proc.displayName() + " returned null PathingCommand"); } - proc.onLostControl(); + proc.onLostControl();*/ } else { inControlThisTick = proc; if (!proc.isTemporary()) {