baritone/src/main/java/baritone/process/GetToBlockProcess.java

256 lines
10 KiB
Java
Raw Normal View History

2018-11-04 05:11:52 +00:00
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.process;
import baritone.Baritone;
2019-02-05 00:27:32 +00:00
import baritone.api.pathing.goals.*;
2018-11-04 05:11:52 +00:00
import baritone.api.process.IGetToBlockProcess;
import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType;
2019-10-06 20:44:37 +00:00
import baritone.api.utils.BlockOptionalMeta;
2019-08-30 22:38:15 +00:00
import baritone.api.utils.BlockOptionalMetaLookup;
2018-12-07 23:53:41 +00:00
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext;
2018-11-04 05:11:52 +00:00
import baritone.utils.BaritoneProcessHelper;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
2018-12-07 23:53:41 +00:00
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ContainerPlayer;
2018-11-04 05:11:52 +00:00
import net.minecraft.util.math.BlockPos;
import java.util.*;
2018-11-04 05:11:52 +00:00
2019-05-20 05:53:09 +00:00
public final class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess {
2018-12-07 23:53:41 +00:00
2019-10-06 20:44:37 +00:00
private BlockOptionalMeta gettingTo;
2018-11-05 22:19:50 +00:00
private List<BlockPos> knownLocations;
2019-02-14 06:39:43 +00:00
private List<BlockPos> blacklist; // locations we failed to calc to
2019-02-05 00:27:32 +00:00
private BlockPos start;
2018-11-04 05:11:52 +00:00
2018-11-05 22:19:50 +00:00
private int tickCount = 0;
private int arrivalTickCount = 0;
2018-11-04 05:11:52 +00:00
public GetToBlockProcess(Baritone baritone) {
2019-03-12 01:24:31 +00:00
super(baritone);
2018-11-04 05:11:52 +00:00
}
@Override
2019-10-06 20:44:37 +00:00
public void getToBlock(BlockOptionalMeta block) {
2018-12-07 23:53:41 +00:00
onLostControl();
2018-11-04 05:11:52 +00:00
gettingTo = block;
2019-02-05 00:27:32 +00:00
start = ctx.playerFeet();
2019-02-14 06:39:43 +00:00
blacklist = new ArrayList<>();
arrivalTickCount = 0;
rescan(new ArrayList<>(), new GetToBlockCalculationContext(false));
2018-11-04 05:11:52 +00:00
}
@Override
public boolean isActive() {
return gettingTo != null;
}
@Override
2019-02-14 06:39:43 +00:00
public synchronized PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
2018-11-04 05:11:52 +00:00
if (knownLocations == null) {
rescan(new ArrayList<>(), new GetToBlockCalculationContext(false));
2018-11-04 05:11:52 +00:00
}
if (knownLocations.isEmpty()) {
2019-03-05 05:30:04 +00:00
if (Baritone.settings().exploreForBlocks.value && !calcFailed) {
2019-02-05 00:27:32 +00:00
return new PathingCommand(new GoalRunAway(1, start) {
@Override
public boolean isInGoal(int x, int y, int z) {
return false;
}
@Override
public double heuristic() {
return Double.NEGATIVE_INFINITY;
}
2019-02-05 00:27:32 +00:00
}, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH);
}
2018-11-05 22:19:50 +00:00
logDirect("No known locations of " + gettingTo + ", canceling GetToBlock");
if (isSafeToCancel) {
onLostControl();
}
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
}
2019-02-08 00:39:15 +00:00
Goal goal = new GoalComposite(knownLocations.stream().map(this::createGoal).toArray(Goal[]::new));
2018-11-05 22:19:50 +00:00
if (calcFailed) {
2019-03-12 03:06:19 +00:00
if (Baritone.settings().blacklistClosestOnFailure.value) {
2019-03-12 03:08:52 +00:00
logDirect("Unable to find any path to " + gettingTo + ", blacklisting presumably unreachable closest instances...");
2019-02-14 06:39:43 +00:00
blacklistClosest();
return onTick(false, isSafeToCancel); // gamer moment
} else {
logDirect("Unable to find any path to " + gettingTo + ", canceling GetToBlock");
if (isSafeToCancel) {
onLostControl();
}
return new PathingCommand(goal, PathingCommandType.CANCEL_AND_SET_GOAL);
2018-11-05 22:19:50 +00:00
}
2018-11-04 05:11:52 +00:00
}
2019-03-05 05:30:04 +00:00
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value;
2018-11-04 05:11:52 +00:00
if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain
2018-11-07 22:09:23 +00:00
List<BlockPos> current = new ArrayList<>(knownLocations);
CalculationContext context = new GetToBlockCalculationContext(true);
Baritone.getExecutor().execute(() -> rescan(current, context));
2018-11-04 05:11:52 +00:00
}
2019-03-12 23:18:48 +00:00
if (goal.isInGoal(ctx.playerFeet()) && goal.isInGoal(baritone.getPathingBehavior().pathStart()) && isSafeToCancel) {
2018-12-07 23:53:41 +00:00
// we're there
2019-10-06 20:44:37 +00:00
if (rightClickOnArrival(gettingTo.getBlock())) {
2018-12-07 23:53:41 +00:00
if (rightClick()) {
onLostControl();
2019-02-08 00:39:15 +00:00
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
2018-12-07 23:53:41 +00:00
}
} else {
onLostControl();
2019-02-08 00:39:15 +00:00
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
2018-12-07 23:53:41 +00:00
}
2018-11-04 18:29:22 +00:00
}
2018-11-05 22:37:05 +00:00
return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH);
2018-11-04 05:11:52 +00:00
}
2019-02-14 12:03:22 +00:00
// blacklist the closest block and its adjacent blocks
public synchronized boolean blacklistClosest() {
2019-02-14 12:03:22 +00:00
List<BlockPos> newBlacklist = new ArrayList<>();
knownLocations.stream().min(Comparator.comparingDouble(ctx.player()::getDistanceSq)).ifPresent(newBlacklist::add);
2019-02-14 06:39:43 +00:00
outer:
while (true) {
for (BlockPos known : knownLocations) {
for (BlockPos blacklist : newBlacklist) {
2019-02-14 12:03:22 +00:00
if (areAdjacent(known, blacklist)) { // directly adjacent
2019-02-14 06:39:43 +00:00
newBlacklist.add(known);
knownLocations.remove(known);
continue outer;
}
}
}
2019-02-22 22:05:29 +00:00
// i can't do break; (codacy gets mad), and i can't do if(true){break}; (codacy gets mad)
// so i will do this
switch (newBlacklist.size()) {
default:
break outer;
2019-02-14 06:39:43 +00:00
}
}
logDebug("Blacklisting unreachable locations " + newBlacklist);
blacklist.addAll(newBlacklist);
return !newBlacklist.isEmpty();
2019-02-14 06:39:43 +00:00
}
// this is to signal to MineProcess that we don't care about the allowBreak setting
// it is NOT to be used to actually calculate a path
public class GetToBlockCalculationContext extends CalculationContext {
public GetToBlockCalculationContext(boolean forUseOnAnotherThread) {
super(GetToBlockProcess.super.baritone, forUseOnAnotherThread);
}
@Override
public double breakCostMultiplierAt(int x, int y, int z, IBlockState current) {
return 1;
}
}
2019-02-14 12:03:22 +00:00
// safer than direct double comparison from distanceSq
private boolean areAdjacent(BlockPos posA, BlockPos posB) {
int diffX = Math.abs(posA.getX() - posB.getX());
int diffY = Math.abs(posA.getY() - posB.getY());
int diffZ = Math.abs(posA.getZ() - posB.getZ());
return (diffX + diffY + diffZ) == 1;
}
2018-11-04 05:11:52 +00:00
@Override
2019-02-14 06:39:43 +00:00
public synchronized void onLostControl() {
2018-11-04 05:11:52 +00:00
gettingTo = null;
knownLocations = null;
2019-02-05 00:27:32 +00:00
start = null;
2019-02-14 06:39:43 +00:00
blacklist = null;
2018-12-07 23:53:41 +00:00
baritone.getInputOverrideHandler().clearAllKeys();
2018-11-04 05:11:52 +00:00
}
2018-11-04 18:29:22 +00:00
@Override
2019-03-13 16:17:25 +00:00
public String displayName0() {
2019-03-12 01:24:31 +00:00
if (knownLocations.isEmpty()) {
return "Exploring randomly to find " + gettingTo + ", no known locations";
}
2019-03-13 16:17:25 +00:00
return "Get To " + gettingTo + ", " + knownLocations.size() + " known locations";
2018-11-04 18:29:22 +00:00
}
2019-02-14 06:39:43 +00:00
private synchronized void rescan(List<BlockPos> known, CalculationContext context) {
List<BlockPos> positions = MineProcess.searchWorld(context, new BlockOptionalMetaLookup(gettingTo), 64, known, blacklist, Collections.emptyList());
2019-02-14 06:39:43 +00:00
positions.removeIf(blacklist::contains);
knownLocations = positions;
2018-11-04 05:11:52 +00:00
}
2018-12-07 23:53:41 +00:00
private Goal createGoal(BlockPos pos) {
2019-10-06 20:44:37 +00:00
if (walkIntoInsteadOfAdjacent(gettingTo.getBlock())) {
2019-02-21 19:25:03 +00:00
return new GoalTwoBlocks(pos);
}
2019-10-06 20:44:37 +00:00
if (blockOnTopMustBeRemoved(gettingTo.getBlock()) && baritone.bsi.get0(pos.up()).isBlockNormalCube()) {
2019-02-21 19:25:03 +00:00
return new GoalBlock(pos.up());
}
return new GoalGetToBlock(pos);
2018-12-07 23:53:41 +00:00
}
private boolean rightClick() {
for (BlockPos pos : knownLocations) {
Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
if (reachable.isPresent()) {
baritone.getLookBehavior().updateTarget(reachable.get(), true);
if (knownLocations.contains(ctx.getSelectedBlock().orElse(null))) {
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); // TODO find some way to right click even if we're in an ESC menu
System.out.println(ctx.player().openContainer);
if (!(ctx.player().openContainer instanceof ContainerPlayer)) {
return true;
}
}
if (arrivalTickCount++ > 20) {
logDirect("Right click timed out");
return true;
}
2018-12-07 23:53:41 +00:00
return false; // trying to right click, will do it next tick or so
}
}
logDirect("Arrived but failed to right click open");
return true;
}
private boolean walkIntoInsteadOfAdjacent(Block block) {
2019-03-05 05:30:04 +00:00
if (!Baritone.settings().enterPortal.value) {
return false;
}
2018-12-07 23:53:41 +00:00
return block == Blocks.PORTAL;
}
private boolean rightClickOnArrival(Block block) {
2019-03-05 05:30:04 +00:00
if (!Baritone.settings().rightClickContainerOnArrival.value) {
return false;
}
2018-12-07 23:53:41 +00:00
return block == Blocks.CRAFTING_TABLE || block == Blocks.FURNACE || block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST;
}
2019-02-21 19:25:03 +00:00
private boolean blockOnTopMustBeRemoved(Block block) {
if (!rightClickOnArrival(block)) { // only if we plan to actually open it on arrival
return false;
}
// only these chests; you can open a crafting table or furnace even with a block on top
return block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST;
}
2018-12-21 05:22:18 +00:00
}