baritone/src/main/java/baritone/pathing/movement/Movement.java

340 lines
12 KiB
Java
Raw Normal View History

2018-08-08 03:16:53 +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
2018-08-08 03:16:53 +00:00
* 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,
2018-08-08 03:16:53 +00:00
* 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.
2018-08-08 03:16:53 +00:00
*
* You should have received a copy of the GNU Lesser General Public License
2018-08-08 03:16:53 +00:00
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
2018-08-22 20:15:56 +00:00
package baritone.pathing.movement;
2018-08-02 04:07:55 +00:00
2018-08-22 20:15:56 +00:00
import baritone.Baritone;
import baritone.behavior.LookBehavior;
import baritone.behavior.LookBehaviorUtils;
2018-08-22 20:15:56 +00:00
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos;
2018-08-28 21:56:21 +00:00
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.chunk.EmptyChunk;
2018-08-06 22:53:35 +00:00
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
2018-08-02 22:35:36 +00:00
import java.util.Optional;
2018-08-22 20:15:56 +00:00
import static baritone.utils.InputOverrideHandler.Input;
2018-08-06 00:37:42 +00:00
2018-08-05 03:01:38 +00:00
public abstract class Movement implements Helper, MovementHelper {
2018-08-28 21:56:21 +00:00
protected static final EnumFacing[] HORIZONTALS = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST};
2018-08-04 22:17:53 +00:00
private MovementState currentState = new MovementState().setStatus(MovementStatus.PREPPING);
protected final BetterBlockPos src;
protected final BetterBlockPos dest;
2018-08-03 03:30:35 +00:00
/**
* The positions that need to be broken before this movement can ensue
*/
protected final BlockPos[] positionsToBreak;
2018-08-03 03:30:35 +00:00
/**
* The position where we need to place a block before this movement can ensue
2018-08-03 03:30:35 +00:00
*/
protected final BlockPos positionToPlace;
private boolean didBreakLastTick;
2018-08-06 00:27:45 +00:00
private Double cost;
2018-09-17 03:16:05 +00:00
public List<BlockPos> toBreakCached = null;
public List<BlockPos> toPlaceCached = null;
public List<BlockPos> toWalkIntoCached = null;
private Boolean calculatedWhileLoaded;
protected Movement(BetterBlockPos src, BetterBlockPos dest, BlockPos[] toBreak, BlockPos toPlace) {
2018-08-02 22:35:36 +00:00
this.src = src;
this.dest = dest;
2018-08-03 03:30:35 +00:00
this.positionsToBreak = toBreak;
this.positionToPlace = toPlace;
2018-08-02 14:59:51 +00:00
}
protected Movement(BetterBlockPos src, BetterBlockPos dest, BlockPos[] toBreak) {
this(src, dest, toBreak, null);
}
public double getCost(CalculationContext context) {
2018-08-06 00:27:45 +00:00
if (cost == null) {
2018-09-17 00:49:19 +00:00
cost = calculateCost(context != null ? context : new CalculationContext());
2018-08-06 00:27:45 +00:00
}
return cost;
}
2018-08-13 18:50:49 +00:00
protected abstract double calculateCost(CalculationContext context);
2018-08-06 00:27:45 +00:00
public double recalculateCost() {
cost = null;
return getCost(null);
}
2018-09-06 14:48:27 +00:00
protected void override(double cost) {
this.cost = cost;
}
public double calculateCostWithoutCaching() {
2018-09-03 16:15:18 +00:00
return calculateCost(new CalculationContext());
}
2018-08-05 03:01:38 +00:00
/**
* Handles the execution of the latest Movement
* State, and offers a Status to the calling class.
*
* @return Status
*/
2018-08-04 18:49:52 +00:00
public MovementStatus update() {
2018-09-15 01:29:35 +00:00
player().capabilities.allowFlying = false;
2018-08-04 22:17:53 +00:00
MovementState latestState = updateState(currentState);
2018-08-07 15:09:27 +00:00
if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true);
}
2018-08-21 23:19:20 +00:00
// If the movement target has to force the new rotations, or we aren't using silent move, then force the rotations
latestState.getTarget().getRotation().ifPresent(rotation ->
LookBehavior.INSTANCE.updateTarget(
rotation,
latestState.getTarget().hasToForceRotations()));
2018-08-06 04:42:17 +00:00
// TODO: calculate movement inputs from latestState.getGoal().position
// latestState.getTarget().position.ifPresent(null); NULL CONSUMER REALLY SHOULDN'T BE THE FINAL THING YOU SHOULD REALLY REPLACE THIS WITH ALMOST ACTUALLY ANYTHING ELSE JUST PLEASE DON'T LEAVE IT AS IT IS THANK YOU KANYE
this.didBreakLastTick = false;
latestState.getInputStates().forEach((input, forced) -> {
if (Baritone.settings().leftClickWorkaround.get()) {
RayTraceResult trace = mc.objectMouseOver;
boolean isBlockTrace = trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK;
boolean isLeftClick = forced && input == Input.CLICK_LEFT;
// If we're forcing left click, we're in a gui screen, and we're looking
// at a block, break the block without a direct game input manipulation.
if (mc.currentScreen != null && isLeftClick && isBlockTrace) {
BlockBreakHelper.tryBreakBlock(trace.getBlockPos(), trace.sideHit);
this.didBreakLastTick = true;
return;
}
}
2018-08-06 01:52:55 +00:00
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced);
});
latestState.getInputStates().replaceAll((input, forced) -> false);
2018-09-08 04:32:25 +00:00
if (!this.didBreakLastTick) {
BlockBreakHelper.stopBreakingBlock();
2018-09-08 04:32:25 +00:00
}
2018-08-02 08:15:51 +00:00
currentState = latestState;
2018-09-08 04:32:25 +00:00
if (isFinished()) {
2018-08-06 01:17:54 +00:00
onFinish(latestState);
2018-09-08 04:32:25 +00:00
}
2018-08-04 22:17:53 +00:00
return currentState.getStatus();
2018-08-02 08:15:51 +00:00
}
2018-08-12 04:27:46 +00:00
protected boolean prepared(MovementState state) {
2018-08-18 19:33:00 +00:00
if (state.getStatus() == MovementStatus.WAITING) {
return true;
}
2018-08-12 15:17:23 +00:00
boolean somethingInTheWay = false;
2018-08-06 04:42:17 +00:00
for (BlockPos blockPos : positionsToBreak) {
if (!MovementHelper.canWalkThrough(blockPos)) {
2018-08-12 15:17:23 +00:00
somethingInTheWay = true;
Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos);
2018-08-06 04:42:17 +00:00
if (reachable.isPresent()) {
MovementHelper.switchToBestToolFor(BlockStateInterface.get(blockPos));
state.setTarget(new MovementState.MovementTarget(reachable.get(), true)).setInput(Input.CLICK_LEFT, true);
2018-08-06 00:37:42 +00:00
return false;
2018-08-06 04:42:17 +00:00
}
//get rekt minecraft
//i'm doing it anyway
//i dont care if theres snow in the way!!!!!!!
//you dont own me!!!!
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(blockPos)), true)
).setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
return false;
2018-08-04 22:17:53 +00:00
}
2018-08-04 18:49:52 +00:00
}
2018-08-12 15:17:23 +00:00
if (somethingInTheWay) {
// There's a block or blocks that we can't walk through, but we have no target rotation to reach any
// So don't return true, actually set state to unreachable
state.setStatus(MovementStatus.UNREACHABLE);
return true;
}
2018-08-04 22:17:53 +00:00
return true;
2018-08-04 18:49:52 +00:00
}
2018-08-02 08:15:51 +00:00
public boolean isFinished() {
2018-08-02 21:28:35 +00:00
return (currentState.getStatus() != MovementStatus.RUNNING
2018-08-06 00:37:42 +00:00
&& currentState.getStatus() != MovementStatus.PREPPING
2018-08-02 21:28:35 +00:00
&& currentState.getStatus() != MovementStatus.WAITING);
}
public BetterBlockPos getSrc() {
2018-08-02 18:12:56 +00:00
return src;
2018-08-02 18:05:47 +00:00
}
public BetterBlockPos getDest() {
2018-08-02 18:12:56 +00:00
return dest;
2018-08-02 18:05:47 +00:00
}
2018-08-03 03:40:27 +00:00
/**
2018-08-06 01:17:54 +00:00
* Run cleanup on state finish and declare success.
2018-08-03 03:40:27 +00:00
*/
2018-08-06 01:17:54 +00:00
public void onFinish(MovementState state) {
state.getInputStates().replaceAll((input, forced) -> false);
state.getInputStates().forEach((input, forced) -> Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced));
2018-08-06 01:17:54 +00:00
}
2018-08-03 03:40:27 +00:00
2018-08-06 02:08:23 +00:00
public void cancel() {
currentState.getInputStates().replaceAll((input, forced) -> false);
currentState.getInputStates().forEach((input, forced) -> Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced));
2018-08-06 02:08:23 +00:00
currentState.setStatus(MovementStatus.CANCELED);
}
2018-08-23 18:14:37 +00:00
public void reset() {
currentState = new MovementState().setStatus(MovementStatus.PREPPING);
}
2018-08-07 00:34:49 +00:00
public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) {
if (positionsToBreak.length == 0) {
return 0;
2018-08-07 00:34:49 +00:00
}
if (positionsToBreak.length == 1) {
return MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[0], true);
2018-08-07 00:34:49 +00:00
}
int firstColumnX = positionsToBreak[0].getX();
int firstColumnZ = positionsToBreak[0].getZ();
int firstColumnMaxY = positionsToBreak[0].getY();
int firstColumnMaximalIndex = 0;
boolean hasSecondColumn = false;
int secondColumnX = -1;
int secondColumnZ = -1;
int secondColumnMaxY = -1;
int secondColumnMaximalIndex = -1;
for (int i = 0; i < positionsToBreak.length; i++) {
BlockPos pos = positionsToBreak[i];
if (pos.getX() == firstColumnX && pos.getZ() == firstColumnZ) {
if (pos.getY() > firstColumnMaxY) {
firstColumnMaxY = pos.getY();
firstColumnMaximalIndex = i;
}
} else {
if (!hasSecondColumn || (pos.getX() == secondColumnX && pos.getZ() == secondColumnZ)) {
if (hasSecondColumn) {
if (pos.getY() > secondColumnMaxY) {
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
hasSecondColumn = true;
secondColumnX = pos.getX();
secondColumnZ = pos.getZ();
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
throw new IllegalStateException("I literally have no idea " + Arrays.asList(positionsToBreak));
2018-08-07 00:34:49 +00:00
}
}
}
2018-08-07 00:34:49 +00:00
double sum = 0;
for (int i = 0; i < positionsToBreak.length; i++) {
sum += MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[i], firstColumnMaximalIndex == i || secondColumnMaximalIndex == i);
2018-08-07 00:34:49 +00:00
if (sum >= COST_INF) {
break;
2018-08-07 00:34:49 +00:00
}
}
return sum;
}
/**
2018-08-02 21:28:35 +00:00
* Calculate latest movement state.
* Gets called once a tick.
*
* @return
*/
2018-08-04 18:49:52 +00:00
public MovementState updateState(MovementState state) {
2018-08-18 19:36:40 +00:00
if (!prepared(state)) {
2018-08-04 18:49:52 +00:00
return state.setStatus(MovementStatus.PREPPING);
2018-08-18 19:36:40 +00:00
} else if (state.getStatus() == MovementStatus.PREPPING) {
state.setStatus(MovementStatus.WAITING);
2018-08-06 00:37:42 +00:00
}
if (state.getStatus() == MovementStatus.WAITING) {
state.setStatus(MovementStatus.RUNNING);
}
2018-08-04 18:49:52 +00:00
return state;
}
2018-08-06 22:53:35 +00:00
public BlockPos getDirection() {
return getDest().subtract(getSrc());
}
public void checkLoadedChunk() {
calculatedWhileLoaded = !(world().getChunk(getDest()) instanceof EmptyChunk);
}
public boolean calculatedWhileLoaded() {
return calculatedWhileLoaded;
}
public List<BlockPos> toBreak() {
2018-08-06 23:09:28 +00:00
if (toBreakCached != null) {
return toBreakCached;
}
List<BlockPos> result = new ArrayList<>();
2018-08-07 00:34:49 +00:00
for (BlockPos positionToBreak : positionsToBreak) {
if (!MovementHelper.canWalkThrough(positionToBreak)) {
2018-08-07 00:34:49 +00:00
result.add(positionToBreak);
2018-08-06 22:53:35 +00:00
}
}
2018-08-06 23:09:28 +00:00
toBreakCached = result;
2018-08-06 22:53:35 +00:00
return result;
}
public List<BlockPos> toPlace() {
2018-08-06 23:09:28 +00:00
if (toPlaceCached != null) {
return toPlaceCached;
}
List<BlockPos> result = new ArrayList<>();
if (positionToPlace != null && !MovementHelper.canWalkOn(positionToPlace)) {
result.add(positionToPlace);
2018-08-06 22:53:35 +00:00
}
2018-08-06 23:09:28 +00:00
toPlaceCached = result;
2018-08-06 22:53:35 +00:00
return result;
}
2018-08-12 15:40:44 +00:00
public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
2018-08-12 15:40:44 +00:00
if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>();
}
return toWalkIntoCached;
}
2018-08-02 04:07:55 +00:00
}