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

558 lines
24 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-22 20:15:56 +00:00
import baritone.Baritone;
2019-09-01 21:45:31 +00:00
import baritone.api.BaritoneAPI;
2019-01-13 03:51:21 +00:00
import baritone.api.IBaritone;
2018-09-25 01:32:39 +00:00
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*;
import baritone.api.utils.input.Input;
2018-08-22 20:15:56 +00:00
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.BlockStateInterface;
import baritone.utils.ToolSet;
import net.minecraft.block.*;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
2018-08-02 17:49:31 +00:00
import net.minecraft.init.Blocks;
2018-08-25 22:24:00 +00:00
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
2019-10-22 20:58:10 +00:00
import net.minecraft.world.IBlockAccess;
import java.util.Optional;
2019-06-06 05:12:28 +00:00
import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP;
/**
* Static helpers for cost calculation
*
* @author leijurv
*/
2018-08-04 02:14:50 +00:00
public interface MovementHelper extends ActionCosts, Helper {
2018-11-13 21:14:29 +00:00
static boolean avoidBreaking(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
2018-08-17 19:24:40 +00:00
Block b = state.getBlock();
2018-09-09 15:57:20 +00:00
return b == Blocks.ICE // ice becomes water, and water can mess up the path
2018-08-18 04:02:41 +00:00
|| b instanceof BlockSilverfish // obvious reasons
// call context.get directly with x,y,z. no need to make 5 new BlockPos for no reason
|| avoidAdjacentBreaking(bsi, x, y + 1, z, true)
|| avoidAdjacentBreaking(bsi, x + 1, y, z, false)
|| avoidAdjacentBreaking(bsi, x - 1, y, z, false)
|| avoidAdjacentBreaking(bsi, x, y, z + 1, false)
|| avoidAdjacentBreaking(bsi, x, y, z - 1, false);
2019-05-01 18:01:00 +00:00
}
static boolean avoidAdjacentBreaking(BlockStateInterface bsi, int x, int y, int z, boolean directlyAbove) {
2019-05-01 18:01:00 +00:00
// returns true if you should avoid breaking a block that's adjacent to this one (e.g. lava that will start flowing if you give it a path)
// this is only called for north, south, east, west, and up. this is NOT called for down.
// we assume that it's ALWAYS okay to break the block thats ABOVE liquid
IBlockState state = bsi.get0(x, y, z);
Block block = state.getBlock();
if (!directlyAbove // it is fine to mine a block that has a falling block directly above, this (the cost of breaking the stacked fallings) is included in cost calculations
// therefore if directlyAbove is true, we will actually ignore if this is falling
&& block instanceof BlockFalling // obviously, this check is only valid for falling blocks
&& Baritone.settings().avoidUpdatingFallingBlocks.value // and if the setting is enabled
&& BlockFalling.canFallThrough(bsi.get0(x, y - 1, z))) { // and if it would fall (i.e. it's unsupported)
return true; // dont break a block that is adjacent to unsupported gravel because it can cause really weird stuff
}
return block instanceof BlockLiquid;
}
2018-11-13 21:14:29 +00:00
static boolean canWalkThrough(IPlayerContext ctx, BetterBlockPos pos) {
return canWalkThrough(new BlockStateInterface(ctx), pos.x, pos.y, pos.z);
2018-08-07 14:39:55 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z) {
return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z));
2018-09-22 16:28:59 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock();
2018-09-22 18:23:26 +00:00
if (block == Blocks.AIR) { // early return for most common case
2018-09-06 14:48:27 +00:00
return true;
}
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL || block == Blocks.COCOA || block instanceof BlockSkull || block instanceof BlockTrapDoor) {
return false;
}
if (Baritone.settings().blocksToAvoid.value.contains(block)) {
return false;
}
if (block instanceof BlockDoor || block instanceof BlockFenceGate) {
2018-09-17 22:46:23 +00:00
// Because there's no nice method in vanilla to check if a door is openable or not, we just have to assume
// that anything that isn't an iron door isn't openable, ignoring that some doors introduced in mods can't
// be opened by just interacting.
return block != Blocks.IRON_DOOR;
}
2019-02-07 00:22:40 +00:00
if (block == Blocks.CARPET) {
return canWalkOn(bsi, x, y - 1, z);
}
if (block instanceof BlockSnow) {
2018-09-22 16:17:28 +00:00
// we've already checked doors and fence gates
// so the only remaining dynamic isPassables are snow and trapdoor
// if they're cached as a top block, we don't know their metadata
// default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
2018-11-23 17:03:51 +00:00
if (!bsi.worldContainsLoadedChunk(x, z)) {
return true;
}
// the check in BlockSnow.isPassable is layers < 5
// while actually, we want < 3 because 3 or greater makes it impassable in a 2 high ceiling
if (state.getValue(BlockSnow.LAYERS) >= 3) {
return false;
2018-09-22 16:17:28 +00:00
}
// ok, it's low enough we could walk through it, but is it supported?
return canWalkOn(bsi, x, y - 1, z);
}
2019-02-26 04:35:06 +00:00
if (isFlowing(x, y, z, state, bsi)) {
2018-08-02 17:55:26 +00:00
return false; // Don't walk through flowing liquids
}
2018-08-28 18:57:31 +00:00
if (block instanceof BlockLiquid) {
2019-03-05 05:30:04 +00:00
if (Baritone.settings().assumeWalkOnWater.value) {
2018-08-28 19:30:08 +00:00
return false;
}
2018-11-13 21:14:29 +00:00
IBlockState up = bsi.get0(x, y + 1, z);
2018-08-28 18:57:31 +00:00
if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
return false;
}
2018-09-22 15:47:02 +00:00
return block == Blocks.WATER || block == Blocks.FLOWING_WATER;
2018-08-28 18:57:31 +00:00
}
2019-10-22 20:58:10 +00:00
return block.isPassable(bsi.access, bsi.isPassableBlockPos.setPos(x, y, z));
}
2018-09-06 14:48:27 +00:00
/**
* canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click),
* not including water, and not including ladders or vines or cobwebs (they slow us down)
*
2019-10-24 20:20:23 +00:00
* @param context Calculation context to provide block state lookup
* @param x The block's x position
* @param y The block's y position
* @param z The block's z position
2018-12-04 00:47:40 +00:00
* @return Whether or not the block at the specified position
2018-09-06 14:48:27 +00:00
*/
2019-10-24 20:20:23 +00:00
static boolean fullyPassable(CalculationContext context, int x, int y, int z) {
return fullyPassable(
context.bsi.access,
2019-10-24 20:20:23 +00:00
context.bsi.isPassableBlockPos.setPos(x, y, z),
context.bsi.get0(x, y, z)
);
2019-10-22 20:58:10 +00:00
}
static boolean fullyPassable(IPlayerContext ctx, BlockPos pos) {
return fullyPassable(ctx.world(), pos, ctx.world().getBlockState(pos));
2018-09-23 19:24:07 +00:00
}
static boolean fullyPassable(IBlockAccess access, BlockPos pos, IBlockState state) {
2018-09-06 14:48:27 +00:00
Block block = state.getBlock();
2018-09-22 18:23:26 +00:00
if (block == Blocks.AIR) { // early return for most common case
2018-09-06 14:48:27 +00:00
return true;
}
2018-09-11 13:37:08 +00:00
// exceptions - blocks that are isPassable true, but we can't actually jump through
2018-09-06 14:48:27 +00:00
if (block == Blocks.FIRE
|| block == Blocks.TRIPWIRE
|| block == Blocks.WEB
|| block == Blocks.VINE
|| block == Blocks.LADDER
|| block == Blocks.COCOA
2018-09-06 14:48:27 +00:00
|| block instanceof BlockDoor
|| block instanceof BlockFenceGate
|| block instanceof BlockSnow
|| block instanceof BlockLiquid
|| block instanceof BlockTrapDoor
2019-02-24 21:43:53 +00:00
|| block instanceof BlockEndPortal
|| block instanceof BlockSkull) {
2018-09-06 14:48:27 +00:00
return false;
}
2018-09-22 16:17:28 +00:00
// door, fence gate, liquid, trapdoor have been accounted for, nothing else uses the world or pos parameters
return block.isPassable(access, pos);
2018-09-06 14:48:27 +00:00
}
2019-09-06 10:59:10 +00:00
static boolean isReplaceable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
// for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case
// all other overrides just return true or false
// the only case to deal with is snow
/*
* public boolean isReplaceable(IBlockAccess worldIn, BlockPos pos)
* {
* return ((Integer)worldIn.getBlockState(pos).getValue(LAYERS)).intValue() == 1;
* }
*/
2018-09-23 02:46:10 +00:00
Block block = state.getBlock();
if (block == Blocks.AIR || isWater(block)) {
// early return for common cases hehe
return true;
}
2018-09-23 02:46:10 +00:00
if (block instanceof BlockSnow) {
// as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
if (!bsi.worldContainsLoadedChunk(x, z)) {
return true;
}
2018-09-23 02:46:10 +00:00
return state.getValue(BlockSnow.LAYERS) == 1;
}
if (block instanceof BlockDoublePlant) {
BlockDoublePlant.EnumPlantType kek = state.getValue(BlockDoublePlant.VARIANT);
return kek == BlockDoublePlant.EnumPlantType.FERN || kek == BlockDoublePlant.EnumPlantType.GRASS;
}
2018-10-15 04:46:41 +00:00
return state.getMaterial().isReplaceable();
}
2019-09-06 10:59:10 +00:00
@Deprecated
static boolean isReplacable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
return isReplaceable(x, y, z, state, bsi);
}
2018-11-13 21:14:29 +00:00
static boolean isDoorPassable(IPlayerContext ctx, BlockPos doorPos, BlockPos playerPos) {
2018-09-08 04:32:25 +00:00
if (playerPos.equals(doorPos)) {
2018-08-15 06:49:08 +00:00
return false;
2018-09-08 04:32:25 +00:00
}
2018-08-25 22:24:00 +00:00
2018-11-13 21:14:29 +00:00
IBlockState state = BlockStateInterface.get(ctx, doorPos);
2018-09-08 04:32:25 +00:00
if (!(state.getBlock() instanceof BlockDoor)) {
2018-08-25 22:24:00 +00:00
return true;
2018-09-08 04:32:25 +00:00
}
2018-08-25 22:24:00 +00:00
return isHorizontalBlockPassable(doorPos, state, playerPos, BlockDoor.OPEN);
}
2018-11-13 21:14:29 +00:00
static boolean isGatePassable(IPlayerContext ctx, BlockPos gatePos, BlockPos playerPos) {
2018-09-08 04:32:25 +00:00
if (playerPos.equals(gatePos)) {
return false;
2018-09-08 04:32:25 +00:00
}
2018-11-13 21:14:29 +00:00
IBlockState state = BlockStateInterface.get(ctx, gatePos);
2018-09-08 04:32:25 +00:00
if (!(state.getBlock() instanceof BlockFenceGate)) {
return true;
2018-09-08 04:32:25 +00:00
}
return state.getValue(BlockFenceGate.OPEN);
}
static boolean isHorizontalBlockPassable(BlockPos blockPos, IBlockState blockState, BlockPos playerPos, PropertyBool propertyOpen) {
2018-09-08 04:32:25 +00:00
if (playerPos.equals(blockPos)) {
return false;
2018-09-08 04:32:25 +00:00
}
EnumFacing.Axis facing = blockState.getValue(BlockHorizontal.FACING).getAxis();
boolean open = blockState.getValue(propertyOpen);
2018-08-25 22:24:00 +00:00
EnumFacing.Axis playerFacing;
if (playerPos.north().equals(blockPos) || playerPos.south().equals(blockPos)) {
2018-08-25 22:24:00 +00:00
playerFacing = EnumFacing.Axis.Z;
} else if (playerPos.east().equals(blockPos) || playerPos.west().equals(blockPos)) {
2018-08-25 22:24:00 +00:00
playerFacing = EnumFacing.Axis.X;
2018-08-15 06:49:08 +00:00
} else {
return true;
}
2018-10-27 23:18:03 +00:00
return (facing == playerFacing) == open;
2018-08-15 06:49:08 +00:00
}
2018-08-03 20:31:33 +00:00
static boolean avoidWalkingInto(Block block) {
2018-09-12 01:33:03 +00:00
return block instanceof BlockLiquid
2018-09-09 15:11:33 +00:00
|| block == Blocks.MAGMA
|| block == Blocks.CACTUS
|| block == Blocks.FIRE
|| block == Blocks.END_PORTAL
|| block == Blocks.WEB;
}
/**
* 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
*
2018-12-04 22:38:08 +00:00
* @param bsi Block state provider
* @param x The block's x position
* @param y The block's y position
* @param z The block's z position
2018-12-04 00:47:40 +00:00
* @param state The state of the block at the specified location
* @return Whether or not the specified block can be walked on
*/
2018-11-13 21:14:29 +00:00
static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock();
2018-09-09 15:11:33 +00:00
if (block == Blocks.AIR || block == Blocks.MAGMA) {
2018-09-22 18:23:26 +00:00
// early return for most common case (air)
// plus magma, which is a normal cube but it hurts you
2018-09-03 16:15:18 +00:00
return false;
}
2018-09-09 15:11:33 +00:00
if (state.isBlockNormalCube()) {
return true;
}
2019-03-05 05:30:04 +00:00
if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this
2018-09-01 20:20:27 +00:00
return true;
}
2018-09-09 15:11:33 +00:00
if (block == Blocks.FARMLAND || block == Blocks.GRASS_PATH) {
2018-09-03 16:15:18 +00:00
return true;
2018-08-06 02:09:29 +00:00
}
2018-09-09 15:11:33 +00:00
if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST) {
2018-09-03 18:27:59 +00:00
return true;
}
if (isWater(block)) {
2018-09-22 15:47:02 +00:00
// since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()"
// BlockPos s that we'd just garbage collect immediately is actually noticeable. I don't even think its a decrease in readability
2018-11-13 21:14:29 +00:00
Block up = bsi.get0(x, y + 1, z).getBlock();
2019-02-26 04:35:06 +00:00
if (up == Blocks.WATERLILY || up == Blocks.CARPET) {
2018-08-28 19:30:08 +00:00
return true;
}
2019-02-26 04:35:06 +00:00
if (isFlowing(x, y, z, state, bsi) || block == Blocks.FLOWING_WATER) {
2018-09-04 20:57:56 +00:00
// the only scenario in which we can walk on flowing water is if it's under still water with jesus off
2019-03-05 05:30:04 +00:00
return isWater(up) && !Baritone.settings().assumeWalkOnWater.value;
2018-09-04 20:57:56 +00:00
}
2018-08-28 19:53:01 +00:00
// if assumeWalkOnWater is on, we can only walk on water if there isn't water above it
// if assumeWalkOnWater is off, we can only walk on water if there is water above it
2019-03-05 05:30:04 +00:00
return isWater(up) ^ Baritone.settings().assumeWalkOnWater.value;
}
2019-03-24 20:53:19 +00:00
if (Baritone.settings().assumeWalkOnLava.value && isLava(block) && !isFlowing(x, y, z, state, bsi)) {
2019-03-24 20:07:08 +00:00
return true;
}
if (block == Blocks.GLASS || block == Blocks.STAINED_GLASS) {
2018-09-09 15:11:33 +00:00
return true;
}
if (block instanceof BlockSlab) {
2019-03-05 05:30:04 +00:00
if (!Baritone.settings().allowWalkOnBottomSlab.value) {
2018-09-09 15:11:33 +00:00
if (((BlockSlab) block).isDouble()) {
return true;
}
return state.getValue(BlockSlab.HALF) != BlockSlab.EnumBlockHalf.BOTTOM;
}
return true;
}
2018-10-27 23:18:03 +00:00
return block instanceof BlockStairs;
}
2018-08-02 17:49:31 +00:00
2018-11-13 21:14:29 +00:00
static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos, IBlockState state) {
return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z, state);
}
2019-04-18 02:46:25 +00:00
static boolean canWalkOn(IPlayerContext ctx, BlockPos pos) {
return canWalkOn(new BlockStateInterface(ctx), pos.getX(), pos.getY(), pos.getZ());
}
2018-11-13 21:14:29 +00:00
static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos) {
return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z);
2018-09-22 16:28:59 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z) {
return canWalkOn(bsi, x, y, z, bsi.get0(x, y, z));
2018-09-22 16:28:59 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z) {
2019-02-07 00:22:40 +00:00
return canPlaceAgainst(bsi, x, y, z, bsi.get0(x, y, z));
2018-08-07 02:48:09 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canPlaceAgainst(BlockStateInterface bsi, BlockPos pos) {
2019-02-07 00:22:40 +00:00
return canPlaceAgainst(bsi, pos.getX(), pos.getY(), pos.getZ());
2018-09-23 02:46:10 +00:00
}
2018-11-13 21:14:29 +00:00
static boolean canPlaceAgainst(IPlayerContext ctx, BlockPos pos) {
return canPlaceAgainst(new BlockStateInterface(ctx), pos);
2018-09-23 02:46:10 +00:00
}
2019-02-07 00:22:40 +00:00
static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
// can we look at the center of a side face of this block and likely be able to place?
// (thats how this check is used)
// therefore dont include weird things that we technically could place against (like carpet) but practically can't
return state.isBlockNormalCube() || state.isFullBlock() || state.getBlock() == Blocks.GLASS || state.getBlock() == Blocks.STAINED_GLASS;
2018-08-28 22:01:24 +00:00
}
2018-09-23 02:46:10 +00:00
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, boolean includeFalling) {
return getMiningDurationTicks(context, x, y, z, context.get(x, y, z), includeFalling);
2018-09-23 02:46:10 +00:00
}
2018-09-23 02:13:59 +00:00
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
Block block = state.getBlock();
2018-12-21 05:22:18 +00:00
if (!canWalkThrough(context.bsi, x, y, z, state)) {
if (block instanceof BlockLiquid) {
return COST_INF;
}
double mult = context.breakCostMultiplierAt(x, y, z, state);
2019-01-09 04:45:02 +00:00
if (mult >= COST_INF) {
2018-08-02 17:49:31 +00:00
return COST_INF;
}
2018-12-21 05:22:18 +00:00
if (avoidBreaking(context.bsi, x, y, z, state)) {
2018-08-14 00:15:59 +00:00
return COST_INF;
}
2018-12-21 05:22:18 +00:00
double strVsBlock = context.toolSet.getStrVsBlock(state);
2018-09-22 16:34:42 +00:00
if (strVsBlock <= 0) {
return COST_INF;
2018-09-08 04:32:25 +00:00
}
double result = 1 / strVsBlock;
2018-12-21 05:22:18 +00:00
result += context.breakBlockAdditionalCost;
2019-01-09 04:45:02 +00:00
result *= mult;
if (includeFalling) {
IBlockState above = context.get(x, y + 1, z);
if (above.getBlock() instanceof BlockFalling) {
2018-09-23 02:13:59 +00:00
result += getMiningDurationTicks(context, x, y + 1, z, above, true);
}
}
return result;
2018-08-02 17:49:31 +00:00
}
return 0; // we won't actually mine it, so don't check fallings above
2018-08-02 17:49:31 +00:00
}
2018-08-04 02:14:50 +00:00
static boolean isBottomSlab(IBlockState state) {
return state.getBlock() instanceof BlockSlab
&& !((BlockSlab) state.getBlock()).isDouble()
&& state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM;
}
2018-08-04 02:14:50 +00:00
/**
* AutoTool for a specific block
*
2018-12-04 00:47:40 +00:00
* @param ctx The player context
2018-12-04 22:38:08 +00:00
* @param b the blockstate to mine
2018-08-04 02:14:50 +00:00
*/
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b) {
2019-09-01 21:45:31 +00:00
switchToBestToolFor(ctx, b, new ToolSet(ctx.player()), BaritoneAPI.getSettings().preferSilkTouch.value);
2018-08-04 02:14:50 +00:00
}
/**
* AutoTool for a specific block with precomputed ToolSet data
*
2018-12-04 00:47:40 +00:00
* @param ctx The player context
2018-12-04 22:38:08 +00:00
* @param b the blockstate to mine
* @param ts previously calculated ToolSet
2018-08-04 02:14:50 +00:00
*/
2019-09-01 21:45:31 +00:00
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b, ToolSet ts, boolean preferSilkTouch) {
ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock(), preferSilkTouch);
2018-08-04 02:14:50 +00:00
}
2018-08-06 22:53:35 +00:00
static void moveTowards(IPlayerContext ctx, MovementState state, BlockPos pos) {
state.setTarget(new MovementTarget(
2019-02-14 05:11:13 +00:00
new Rotation(RotationUtils.calcRotationFromVec3d(ctx.playerHead(),
2018-10-14 05:55:30 +00:00
VecUtils.getBlockPosCenter(pos),
2019-02-14 05:11:13 +00:00
ctx.playerRotations()).getYaw(), ctx.player().rotationPitch),
false
)).setInput(Input.MOVE_FORWARD, true);
}
/**
* Returns whether or not the specified block is
* water, regardless of whether or not it is flowing.
*
* @param b The block
* @return Whether or not the block is water
*/
static boolean isWater(Block b) {
return b == Blocks.FLOWING_WATER || b == Blocks.WATER;
}
/**
* Returns whether or not the block at the specified pos is
* water, regardless of whether or not it is flowing.
*
2018-11-13 21:14:29 +00:00
* @param ctx The player context
* @param bp The block pos
* @return Whether or not the block is water
*/
2018-11-13 21:14:29 +00:00
static boolean isWater(IPlayerContext ctx, BlockPos bp) {
return isWater(BlockStateInterface.getBlock(ctx, bp));
}
static boolean isLava(Block b) {
return b == Blocks.FLOWING_LAVA || b == Blocks.LAVA;
}
/**
* Returns whether or not the specified pos has a liquid
*
2018-11-13 21:14:29 +00:00
* @param ctx The player context
* @param p The pos
* @return Whether or not the block is a liquid
*/
2018-11-13 21:14:29 +00:00
static boolean isLiquid(IPlayerContext ctx, BlockPos p) {
return BlockStateInterface.getBlock(ctx, p) instanceof BlockLiquid;
}
2019-02-26 04:35:06 +00:00
static boolean possiblyFlowing(IBlockState state) {
// Will be IFluidState in 1.13
return state.getBlock() instanceof BlockLiquid
&& state.getValue(BlockLiquid.LEVEL) != 0;
}
2019-02-26 04:35:06 +00:00
static boolean isFlowing(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
if (!(state.getBlock() instanceof BlockLiquid)) {
return false;
}
if (state.getValue(BlockLiquid.LEVEL) != 0) {
return true;
}
return possiblyFlowing(bsi.get0(x + 1, y, z))
|| possiblyFlowing(bsi.get0(x - 1, y, z))
|| possiblyFlowing(bsi.get0(x, y, z + 1))
|| possiblyFlowing(bsi.get0(x, y, z - 1));
}
2019-01-13 03:51:21 +00:00
static PlaceResult attemptToPlaceABlock(MovementState state, IBaritone baritone, BlockPos placeAt, boolean preferDown) {
IPlayerContext ctx = baritone.getPlayerContext();
Optional<Rotation> direct = RotationUtils.reachable(ctx, placeAt); // we assume that if there is a block there, it must be replacable
boolean found = false;
if (direct.isPresent()) {
state.setTarget(new MovementState.MovementTarget(direct.get(), true));
found = true;
}
for (int i = 0; i < 5; i++) {
2019-06-06 05:12:28 +00:00
BlockPos against1 = placeAt.offset(HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
if (MovementHelper.canPlaceAgainst(ctx, against1)) {
2019-03-22 22:45:34 +00:00
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;
}
double faceX = (placeAt.getX() + against1.getX() + 1.0D) * 0.5D;
2019-08-01 05:17:44 +00:00
double faceY = (placeAt.getY() + against1.getY() + 0.5D) * 0.5D;
double faceZ = (placeAt.getZ() + against1.getZ() + 1.0D) * 0.5D;
Rotation place = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations());
RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance());
if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(placeAt)) {
state.setTarget(new MovementState.MovementTarget(place, true));
found = true;
if (!preferDown) {
// if preferDown is true, we want the last option
// if preferDown is false, we want the first
break;
}
}
}
}
if (ctx.getSelectedBlock().isPresent()) {
BlockPos selectedBlock = ctx.getSelectedBlock().get();
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))) {
2019-03-22 22:45:34 +00:00
((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ());
return PlaceResult.READY_TO_PLACE;
}
}
2019-03-22 22:45:34 +00:00
if (found) {
((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(true, placeAt.getX(), placeAt.getY(), placeAt.getZ());
return PlaceResult.ATTEMPTING;
}
return PlaceResult.NO_OPTION;
}
enum PlaceResult {
READY_TO_PLACE, ATTEMPTING, NO_OPTION;
}
}