baritone/src/main/java/baritone/bot/pathing/movement/MovementHelper.java

308 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 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,
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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
2018-08-02 21:28:35 +00:00
package baritone.bot.pathing.movement;
2018-08-14 00:15:59 +00:00
import baritone.bot.Baritone;
import baritone.bot.behavior.impl.LookBehaviorUtils;
import baritone.bot.pathing.movement.MovementState.MovementTarget;
2018-08-07 13:16:38 +00:00
import baritone.bot.pathing.movement.movements.MovementDescend;
import baritone.bot.pathing.movement.movements.MovementFall;
import baritone.bot.utils.*;
import net.minecraft.block.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
2018-08-06 22:53:35 +00:00
import net.minecraft.client.entity.EntityPlayerSP;
2018-08-04 02:14:50 +00:00
import net.minecraft.entity.Entity;
2018-08-02 17:49:31 +00:00
import net.minecraft.init.Blocks;
2018-08-06 22:53:35 +00:00
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
2018-08-04 02:14:50 +00:00
import net.minecraft.util.math.RayTraceResult;
import java.util.Optional;
/**
* Static helpers for cost calculation
*
* @author leijurv
*/
2018-08-04 02:14:50 +00:00
public interface MovementHelper extends ActionCosts, Helper {
2018-08-17 19:24:40 +00:00
static boolean avoidBreaking(BlockPos pos, IBlockState state) {
Block b = state.getBlock();
BlockPos below = new BlockPos(pos.getX(), pos.getY() - 1, pos.getZ());
2018-08-02 17:56:26 +00:00
return Blocks.ICE.equals(b) // ice becomes water, and water can mess up the path
2018-08-04 22:17:53 +00:00
|| b instanceof BlockSilverfish
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY() + 1, pos.getZ()))//don't break anything touching liquid on any side
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX() + 1, pos.getY(), pos.getZ()))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX() - 1, pos.getY(), pos.getZ()))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY(), pos.getZ() + 1))
|| BlockStateInterface.isLiquid(new BlockPos(pos.getX(), pos.getY(), pos.getZ() - 1))
|| (!(b instanceof BlockLilyPad && BlockStateInterface.isWater(below)) && BlockStateInterface.isLiquid(below));//if it's a lilypad above water, it's ok to break, otherwise don't break if its liquid
}
/**
* Can I walk through this block? e.g. air, saplings, torches, etc
*
* @param pos
* @return
*/
static boolean canWalkThrough(BlockPos pos) {
2018-08-17 19:24:40 +00:00
return canWalkThrough(pos, BlockStateInterface.get(pos));
2018-08-07 14:39:55 +00:00
}
static boolean canWalkThrough(BlockPos pos, IBlockState state) {
Block block = state.getBlock();
2018-08-04 22:17:53 +00:00
if (block instanceof BlockLilyPad
|| block instanceof BlockFire
|| block instanceof BlockTripWire
|| block instanceof BlockWeb
|| block instanceof BlockEndPortal) {//you can't actually walk through a lilypad from the side, and you shouldn't walk through fire
return false;
}
2018-08-08 22:56:13 +00:00
if (BlockStateInterface.isFlowing(state) || BlockStateInterface.isLiquid(pos.up())) {
2018-08-02 17:55:26 +00:00
return false; // Don't walk through flowing liquids
}
2018-08-15 06:49:08 +00:00
if (block instanceof BlockDoor) {
return true; // we can just open the door
}
return block.isPassable(mc.world, pos);
}
2018-08-15 06:49:08 +00:00
static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
IBlockState door = BlockStateInterface.get(doorPos);
if (!(door.getBlock() instanceof BlockDoor)) {
return true;
}
String facing = door.getValue(BlockDoor.FACING).getName();
boolean open = door.getValue(BlockDoor.OPEN).booleanValue();
/**
* yes this is dumb
* change it if you want
*/
String playerFacing = "";
if (playerPos.equals(doorPos)) {
return false;
}
if (playerPos.north().equals(doorPos) || playerPos.south().equals(doorPos)) {
playerFacing = "northsouth";
2018-08-15 13:50:43 +00:00
} else if (playerPos.east().equals(doorPos) || playerPos.west().equals(doorPos)) {
2018-08-15 06:49:08 +00:00
playerFacing = "eastwest";
} else {
return true;
}
if (facing == "north" || facing == "south") {
if (open) {
return playerFacing == "northsouth";
} else {
return playerFacing == "eastwest";
}
} else {
if (open) {
return playerFacing == "eastwest";
} else {
return playerFacing == "northsouth";
}
}
}
2018-08-03 20:31:33 +00:00
static boolean avoidWalkingInto(Block block) {
return BlockStateInterface.isLava(block)
2018-08-03 20:31:33 +00:00
|| block instanceof BlockCactus
2018-08-04 22:17:53 +00:00
|| block instanceof BlockFire
|| block instanceof BlockEndPortal
2018-08-17 19:24:40 +00:00
|| block instanceof BlockWeb;
}
/**
* Can I walk on this block without anything weird happening like me falling
* through? Includes water because we know that we automatically jump on
2018-08-17 19:24:40 +00:00
* water
*
* @return
*/
2018-08-07 02:48:09 +00:00
static boolean canWalkOn(BlockPos pos, IBlockState state) {
Block block = state.getBlock();
2018-08-17 19:24:40 +00:00
if (block instanceof BlockLadder || block instanceof BlockVine) { // TODO reconsider this
return true;
}
if (block instanceof BlockGlass || block instanceof BlockStainedGlass) {
return true;
}
if (Blocks.FARMLAND.equals(block) || Blocks.GRASS_PATH.equals(block)) {
return true;
}
2018-08-06 02:09:29 +00:00
if (block instanceof BlockAir) {
return false;
}
if (BlockStateInterface.isWater(block)) {
return BlockStateInterface.isWater(pos.up()); // You can only walk on water if there is water above it
}
2018-08-17 19:24:40 +00:00
if (Blocks.MAGMA.equals(block)) {
2018-08-11 22:03:14 +00:00
return false;
}
return state.isBlockNormalCube() && !BlockStateInterface.isLava(block);
}
2018-08-02 17:49:31 +00:00
2018-08-07 02:48:09 +00:00
static boolean canWalkOn(BlockPos pos) {
2018-08-17 19:24:40 +00:00
return canWalkOn(pos, BlockStateInterface.get(pos));
2018-08-07 02:48:09 +00:00
}
2018-08-02 17:49:31 +00:00
static boolean canFall(BlockPos pos) {
return BlockStateInterface.get(pos).getBlock() instanceof BlockFalling;
}
static double getMiningDurationTicks(CalculationContext context, BlockPos position) {
IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(context, position, state);
2018-08-17 19:24:40 +00:00
}
static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state) {
Block block = state.getBlock();
if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) { // TODO is the air check really necessary? Isn't air canWalkThrough?
if (!context.allowBreak()) {
2018-08-02 17:49:31 +00:00
return COST_INF;
}
2018-08-17 19:24:40 +00:00
if (avoidBreaking(position, state)) {
2018-08-14 00:15:59 +00:00
return COST_INF;
}
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
return m / context.getToolSet().getStrVsBlock(state, position);
2018-08-02 17:49:31 +00:00
}
return 0;
}
2018-08-04 02:14:50 +00:00
/**
* The entity the player is currently looking at
*
* @return the entity object
2018-08-04 02:14:50 +00:00
*/
static Optional<Entity> whatEntityAmILookingAt() {
2018-08-04 02:14:50 +00:00
if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
return Optional.of(mc.objectMouseOver.entityHit);
2018-08-04 02:14:50 +00:00
}
return Optional.empty();
2018-08-04 02:14:50 +00:00
}
/**
* AutoTool
*/
static void switchToBestTool() {
LookBehaviorUtils.getSelectedBlock().ifPresent(pos -> {
IBlockState state = BlockStateInterface.get(pos);
if (state.getBlock().equals(Blocks.AIR)) {
return;
}
switchToBestToolFor(state);
});
2018-08-04 02:14:50 +00:00
}
/**
* AutoTool for a specific block
*
* @param b the blockstate to mine
*/
static void switchToBestToolFor(IBlockState b) {
switchToBestToolFor(b, new ToolSet());
}
/**
* AutoTool for a specific block with precomputed ToolSet data
*
* @param b the blockstate to mine
* @param ts previously calculated ToolSet
*/
static void switchToBestToolFor(IBlockState b, ToolSet ts) {
mc.player.inventory.currentItem = ts.getBestSlot(b);
2018-08-04 02:14:50 +00:00
}
2018-08-06 22:53:35 +00:00
2018-08-11 22:03:14 +00:00
static boolean throwaway(boolean select) {
2018-08-06 22:53:35 +00:00
EntityPlayerSP p = Minecraft.getMinecraft().player;
NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
// this usage of settings() is okay because it's only called once during pathing
// (while creating the CalculationContext at the very beginning)
// and then it's called during execution
// since this function is never called during cost calculation, we don't need to migrate
// acceptableThrowawayItems to the CalculationContext
if (Baritone.settings().acceptableThrowawayItems.get().contains(item.getItem())) {
2018-08-11 22:03:14 +00:00
if (select) {
p.inventory.currentItem = i;
}
2018-08-06 22:53:35 +00:00
return true;
}
}
return false;
}
2018-08-14 18:25:30 +00:00
static void moveTowards(MovementState state, BlockPos pos) {
state.setTarget(new MovementTarget(new Rotation(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
2018-08-08 22:31:41 +00:00
Utils.getBlockPosCenter(pos),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)).getFirst(), mc.player.rotationPitch))
).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
}
2018-08-14 17:47:31 +00:00
static Movement generateMovementFallOrDescend(BlockPos pos, BlockPos dest, CalculationContext calcContext) {
2018-08-13 15:28:43 +00:00
// A
//SA
// B
// B
// C
// D
//if S is where you start, both of B need to be air for a movementfall
//A is plausibly breakable by either descend or fall
//C, D, etc determine the length of the fall
for (int i = 1; i < 3; i++) {
if (!canWalkThrough(dest.down(i))) {
//if any of these two (B in the diagram) aren't air
//have to do a descend, because fall is impossible
//this doesn't guarantee descend is possible, it just guarantees fall is impossible
2018-08-08 22:55:04 +00:00
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1
2018-08-07 13:16:38 +00:00
}
}
// we're clear for a fall 2
// let's see how far we can fall
for (int fallHeight = 3; true; fallHeight++) {
BlockPos onto = dest.down(fallHeight);
if (onto.getY() < 0) {
2018-08-07 13:16:38 +00:00
break;
}
2018-08-07 14:39:55 +00:00
IBlockState ontoBlock = BlockStateInterface.get(onto);
if (BlockStateInterface.isWater(ontoBlock.getBlock())) {
2018-08-07 13:16:38 +00:00
return new MovementFall(pos, onto);
}
2018-08-07 14:39:55 +00:00
if (canWalkThrough(onto, ontoBlock)) {
continue;
}
if (canWalkOn(onto, ontoBlock)) {
2018-08-08 22:41:58 +00:00
if (calcContext.hasWaterBucket() || fallHeight <= 4) {
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
return new MovementFall(pos, onto.up());
} else {
return null;
}
2018-08-07 13:16:38 +00:00
}
break;
}
return null;
}
}