misc movement cleanups

This commit is contained in:
Leijurv 2018-08-17 12:24:40 -07:00
parent c635ba69fd
commit e71783105c
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
13 changed files with 104 additions and 38 deletions

View File

@ -51,7 +51,7 @@ public class Settings {
)); ));
public Setting<Boolean> renderGoal = new Setting<>(true); public Setting<Boolean> renderGoal = new Setting<>(true);
public Setting<Integer> pathingMaxChunkBorderFetch = new Setting<>(50); public Setting<Integer> pathingMaxChunkBorderFetch = new Setting<>(50);
public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.9); public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.9); // see issue #18
public Setting<Float> pathRenderLineWidth = new Setting<>(5F); public Setting<Float> pathRenderLineWidth = new Setting<>(5F);
public Setting<Float> goalRenderLineWidth = new Setting<>(3F); public Setting<Float> goalRenderLineWidth = new Setting<>(3F);

View File

@ -151,6 +151,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost); throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost);
} }
if (favoring && favored.contains(dest)) { if (favoring && favored.contains(dest)) {
// see issue #18
actionCost *= favorCoeff; actionCost *= favorCoeff;
} }
PathNode neighbor = getNodeAtPosition(dest); PathNode neighbor = getNodeAtPosition(dest);

View File

@ -24,7 +24,7 @@ public interface ActionCosts extends ActionCostsButOnlyTheOnesThatMakeMickeyDieI
*/ */
double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633 double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633
double WALK_ONE_IN_WATER_COST = 20 / 2.2; double WALK_ONE_IN_WATER_COST = 20 / 2.2;
double JUMP_ONE_BLOCK_COST = 5.72854;//see below calculation for fall. 1.25 blocks double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_IN_WATER_COST; // TODO issue #7
double LADDER_UP_ONE_COST = 20 / 2.35; double LADDER_UP_ONE_COST = 20 / 2.35;
double LADDER_DOWN_ONE_COST = 20 / 3.0; double LADDER_DOWN_ONE_COST = 20 / 3.0;
double SNEAK_ONE_BLOCK_COST = 20 / 1.3; double SNEAK_ONE_BLOCK_COST = 20 / 1.3;

View File

@ -20,6 +20,23 @@ package baritone.bot.pathing.movement;
public interface ActionCostsButOnlyTheOnesThatMakeMickeyDieInside { public interface ActionCostsButOnlyTheOnesThatMakeMickeyDieInside {
double[] FALL_N_BLOCKS_COST = generateFallNBlocksCost(); double[] FALL_N_BLOCKS_COST = generateFallNBlocksCost();
double FALL_1_25_BLOCKS_COST = distanceToTicks(1.25);
double FALL_0_25_BLOCKS_COST = distanceToTicks(0.25);
/**
* When you hit space, you get enough upward velocity to go 1.25 blocks
* Then, you fall the remaining 0.25 to get on the surface, on block higher.
* Since parabolas are symmetric, the amount of time it takes to ascend up from 1 to 1.25
* will be the same amount of time that it takes to fall back down from 1.25 to 1.
* And the same applies to the overall shape, if it takes X ticks to fall back down 1.25 blocks,
* it will take X ticks to reach the peak of your 1.25 block leap.
* Therefore, the part of your jump from y=0 to y=1.25 takes distanceToTicks(1.25) ticks,
* and the sub-part from y=1 to y=1.25 takes distanceToTicks(0.25) ticks.
* Therefore, the other sub-part, from y=0 to y-1, takes distanceToTicks(1.25)-distanceToTicks(0.25) ticks.
* That's why JUMP_ONE_BLOCK_COST = FALL_1_25_BLOCKS_COST - FALL_0_25_BLOCKS_COST
*/
double JUMP_ONE_BLOCK_COST = FALL_1_25_BLOCKS_COST - FALL_0_25_BLOCKS_COST;
static double[] generateFallNBlocksCost() { static double[] generateFallNBlocksCost() {
double[] costs = new double[257]; double[] costs = new double[257];
for (int i = 0; i < 257; i++) { for (int i = 0; i < 257; i++) {

View File

@ -43,8 +43,8 @@ import java.util.Optional;
*/ */
public interface MovementHelper extends ActionCosts, Helper { public interface MovementHelper extends ActionCosts, Helper {
static boolean avoidBreaking(BlockPos pos) { static boolean avoidBreaking(BlockPos pos, IBlockState state) {
Block b = BlockStateInterface.getBlock(pos); Block b = state.getBlock();
BlockPos below = new BlockPos(pos.getX(), pos.getY() - 1, pos.getZ()); BlockPos below = new BlockPos(pos.getX(), pos.getY() - 1, pos.getZ());
return Blocks.ICE.equals(b) // ice becomes water, and water can mess up the path return Blocks.ICE.equals(b) // ice becomes water, and water can mess up the path
|| b instanceof BlockSilverfish || b instanceof BlockSilverfish
@ -63,8 +63,7 @@ public interface MovementHelper extends ActionCosts, Helper {
* @return * @return
*/ */
static boolean canWalkThrough(BlockPos pos) { static boolean canWalkThrough(BlockPos pos) {
IBlockState state = BlockStateInterface.get(pos); return canWalkThrough(pos, BlockStateInterface.get(pos));
return canWalkThrough(pos, state);
} }
static boolean canWalkThrough(BlockPos pos, IBlockState state) { static boolean canWalkThrough(BlockPos pos, IBlockState state) {
@ -126,21 +125,20 @@ public interface MovementHelper extends ActionCosts, Helper {
|| block instanceof BlockCactus || block instanceof BlockCactus
|| block instanceof BlockFire || block instanceof BlockFire
|| block instanceof BlockEndPortal || block instanceof BlockEndPortal
|| block instanceof BlockWeb || block instanceof BlockWeb;
|| block instanceof BlockMagma;
} }
/** /**
* Can I walk on this block without anything weird happening like me falling * Can I walk on this block without anything weird happening like me falling
* through? Includes water because we know that we automatically jump on * through? Includes water because we know that we automatically jump on
* lava * water
* *
* @return * @return
*/ */
static boolean canWalkOn(BlockPos pos, IBlockState state) { static boolean canWalkOn(BlockPos pos, IBlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
if (block instanceof BlockLadder || block instanceof BlockVine) { if (block instanceof BlockLadder || block instanceof BlockVine) { // TODO reconsider this
return true; return true;
} }
if (block instanceof BlockAir) { if (block instanceof BlockAir) {
@ -149,15 +147,14 @@ public interface MovementHelper extends ActionCosts, Helper {
if (BlockStateInterface.isWater(block)) { if (BlockStateInterface.isWater(block)) {
return BlockStateInterface.isWater(pos.up()); // You can only walk on water if there is water above it return BlockStateInterface.isWater(pos.up()); // You can only walk on water if there is water above it
} }
if (block.equals(Blocks.MAGMA)) { if (Blocks.MAGMA.equals(block)) {
return false; return false;
} }
return state.isBlockNormalCube() && !BlockStateInterface.isLava(block); return state.isBlockNormalCube() && !BlockStateInterface.isLava(block);
} }
static boolean canWalkOn(BlockPos pos) { static boolean canWalkOn(BlockPos pos) {
IBlockState state = BlockStateInterface.get(pos); return canWalkOn(pos, BlockStateInterface.get(pos));
return canWalkOn(pos, state);
} }
static boolean canFall(BlockPos pos) { static boolean canFall(BlockPos pos) {
@ -166,12 +163,16 @@ public interface MovementHelper extends ActionCosts, Helper {
static double getMiningDurationTicks(ToolSet ts, BlockPos position) { static double getMiningDurationTicks(ToolSet ts, BlockPos position) {
IBlockState state = BlockStateInterface.get(position); IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(ts, position, state);
}
static double getMiningDurationTicks(ToolSet ts, BlockPos position, IBlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
if (!block.equals(Blocks.AIR) && !canWalkThrough(position)) { if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) {
if (!Baritone.settings().allowBreak.get()) { if (!Baritone.settings().allowBreak.get()) {
return COST_INF; return COST_INF;
} }
if (avoidBreaking(position)) { if (avoidBreaking(position, state)) {
return COST_INF; return COST_INF;
} }
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1;

View File

@ -26,6 +26,7 @@ import baritone.bot.pathing.movement.MovementState.MovementStatus;
import baritone.bot.utils.BlockStateInterface; import baritone.bot.utils.BlockStateInterface;
import baritone.bot.utils.InputOverrideHandler; import baritone.bot.utils.InputOverrideHandler;
import baritone.bot.utils.Utils; import baritone.bot.utils.Utils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling; import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@ -82,14 +83,29 @@ public class MovementAscend extends Movement {
return COST_INF; return COST_INF;
} }
if (BlockStateInterface.get(src.up(3)).getBlock() instanceof BlockFalling) {//it would fall on us and possibly suffocate us if (BlockStateInterface.get(src.up(3)).getBlock() instanceof BlockFalling) {//it would fall on us and possibly suffocate us
// HOWEVER, we assume that we're standing in the start position
// that means that src and src.up(1) are both air
// maybe they aren't now, but they will be by the time this starts
Block srcUp = BlockStateInterface.get(src.up(1)).getBlock();
Block srcUp2 = BlockStateInterface.get(src.up(2)).getBlock();
if (!(srcUp instanceof BlockFalling) || !(srcUp2 instanceof BlockFalling)) {
// if both of those are BlockFalling, that means that by standing on src
// (the presupposition of this Movement)
// we have necessarily already cleared the entire BlockFalling stack
// on top of our head
// but if either of them aren't BlockFalling, that means we're still in suffocation danger
// so don't do it
return COST_INF; return COST_INF;
} }
double halfWalk = WALK_ONE_BLOCK_COST / 2;
if (toPlace.getBlock().equals(Blocks.SOUL_SAND)) {
halfWalk *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST;
} }
// we walk half the block to get to the edge, then we walk the other half while simultaneously jumping (math.max because of how it's in parallel) // TODO maybe change behavior if src.down() is soul sand?
return halfWalk + Math.max(JUMP_ONE_BLOCK_COST, halfWalk) + getTotalHardnessOfBlocksToBreak(context.getToolSet()); double walk = WALK_ONE_BLOCK_COST;
if (toPlace.getBlock().equals(Blocks.SOUL_SAND)) {
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
}
// we hit space immediately on entering this action
return Math.max(JUMP_ONE_BLOCK_COST, walk) + getTotalHardnessOfBlocksToBreak(context.getToolSet());
} }
@Override @Override

View File

@ -48,7 +48,8 @@ public class MovementDescend extends Movement {
// we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel) // we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel)
double walk = WALK_OFF_BLOCK_COST; double walk = WALK_OFF_BLOCK_COST;
if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) { if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) {
walk *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST; // use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
} }
return walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST) + getTotalHardnessOfBlocksToBreak(context.getToolSet()); return walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST) + getTotalHardnessOfBlocksToBreak(context.getToolSet());
} }

View File

@ -78,11 +78,15 @@ public class MovementDiagonal extends Movement {
return COST_INF; return COST_INF;
} }
double multiplier = WALK_ONE_BLOCK_COST; double multiplier = WALK_ONE_BLOCK_COST;
// for either possible soul sand, that affects half of our walking
if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) { if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) {
multiplier *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} else if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) {
multiplier *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST;
} }
if (BlockStateInterface.get(src.down()).getBlock().equals(Blocks.SOUL_SAND)) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (BlockStateInterface.get(positionsToBreak[2].down()).getBlock() instanceof BlockMagma) { if (BlockStateInterface.get(positionsToBreak[2].down()).getBlock() instanceof BlockMagma) {
return COST_INF; return COST_INF;
} }
@ -110,12 +114,15 @@ public class MovementDiagonal extends Movement {
return COST_INF; return COST_INF;
} }
} }
if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) {
// ignore previous multiplier
// whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// not even touching the blocks below
multiplier = WALK_ONE_IN_WATER_COST;
}
if (optionA != 0 || optionB != 0) { if (optionA != 0 || optionB != 0) {
multiplier *= SQRT_2 - 0.001; // TODO tune multiplier *= SQRT_2 - 0.001; // TODO tune
} }
if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) {
multiplier *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST;
}
if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) { if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) {
// if we aren't edging around anything, and we aren't in water or soul sand // if we aren't edging around anything, and we aren't in water or soul sand
// we can sprint =D // we can sprint =D

View File

@ -25,6 +25,7 @@ import baritone.bot.utils.BlockStateInterface;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder; import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine; import net.minecraft.block.BlockVine;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
public class MovementDownward extends Movement { public class MovementDownward extends Movement {
@ -40,12 +41,13 @@ public class MovementDownward extends Movement {
if (!MovementHelper.canWalkOn(dest.down())) { if (!MovementHelper.canWalkOn(dest.down())) {
return COST_INF; return COST_INF;
} }
Block td = BlockStateInterface.get(dest).getBlock(); IBlockState d = BlockStateInterface.get(dest);
Block td = d.getBlock();
boolean ladder = td instanceof BlockLadder || td instanceof BlockVine; boolean ladder = td instanceof BlockLadder || td instanceof BlockVine;
if (ladder) { if (ladder) {
return LADDER_DOWN_ONE_COST; return LADDER_DOWN_ONE_COST;
} else { } else {
return FALL_N_BLOCKS_COST[1] + getTotalHardnessOfBlocksToBreak(context.getToolSet()); return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context.getToolSet(), dest, d);
} }
} }

View File

@ -49,6 +49,9 @@ public class MovementFall extends Movement {
} }
double placeBucketCost = 0.0; double placeBucketCost = 0.0;
if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > 3) { if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > 3) {
if (!context.hasWaterBucket()) {
return COST_INF;
}
placeBucketCost = ActionCosts.PLACE_ONE_BLOCK_COST; placeBucketCost = ActionCosts.PLACE_ONE_BLOCK_COST;
} }
double frontTwo = MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[1]); double frontTwo = MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[1]);
@ -56,6 +59,11 @@ public class MovementFall extends Movement {
return COST_INF; return COST_INF;
} }
for (int i = 2; i < positionsToBreak.length; i++) { for (int i = 2; i < positionsToBreak.length; i++) {
// TODO is this the right check here?
// miningDurationTicks is all right, but shouldn't it be canWalkThrough instead?
// lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage
// same thing for falling through water... we can't actually do that
// and falling through signs is possible, but they do have a mining duration, right?
if (MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[i]) > 0) { if (MovementHelper.getMiningDurationTicks(context.getToolSet(), positionsToBreak[i]) > 0) {
//can't break while falling //can't break while falling
return COST_INF; return COST_INF;

View File

@ -72,9 +72,16 @@ public class MovementTraverse extends Movement {
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
IBlockState destOn = BlockStateInterface.get(positionsToPlace[0]); IBlockState destOn = BlockStateInterface.get(positionsToPlace[0]);
if (MovementHelper.canWalkOn(positionsToPlace[0], destOn)) {//this is a walk, not a bridge if (MovementHelper.canWalkOn(positionsToPlace[0], destOn)) {//this is a walk, not a bridge
double WC = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock()) ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST; double WC = WALK_ONE_BLOCK_COST;
if (destOn.getBlock().equals(Blocks.SOUL_SAND)) { if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC *= WALK_ONE_IN_WATER_COST / WALK_ONE_BLOCK_COST; WC = WALK_ONE_IN_WATER_COST;
} else {
if (Blocks.SOUL_SAND.equals(destOn.getBlock())) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (Blocks.SOUL_SAND.equals(BlockStateInterface.get(src.down()).getBlock())) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
} }
if (MovementHelper.canWalkThrough(positionsToBreak[0]) && MovementHelper.canWalkThrough(positionsToBreak[1])) { if (MovementHelper.canWalkThrough(positionsToBreak[0]) && MovementHelper.canWalkThrough(positionsToBreak[1])) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) { if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) {
@ -89,9 +96,8 @@ public class MovementTraverse extends Movement {
//Out.log("Can't walk through " + blocksToBreak[0] + " (hardness" + hardness1 + ") or " + blocksToBreak[1] + " (hardness " + hardness2 + ")"); //Out.log("Can't walk through " + blocksToBreak[0] + " (hardness" + hardness1 + ") or " + blocksToBreak[1] + " (hardness " + hardness2 + ")");
return WC + getTotalHardnessOfBlocksToBreak(context.getToolSet()); return WC + getTotalHardnessOfBlocksToBreak(context.getToolSet());
} else {//this is a bridge, so we need to place a block } else {//this is a bridge, so we need to place a block
//return 1000000; Block srcDown = BlockStateInterface.get(src.down()).getBlock();
Block f = BlockStateInterface.get(src.down()).getBlock(); if (srcDown instanceof BlockLadder || srcDown instanceof BlockVine) {
if (f instanceof BlockLadder || f instanceof BlockVine) {
return COST_INF; return COST_INF;
} }
IBlockState pp0 = BlockStateInterface.get(positionsToPlace[0]); IBlockState pp0 = BlockStateInterface.get(positionsToPlace[0]);

View File

@ -151,7 +151,12 @@ public final class InputOverrideHandler implements Helper {
/** /**
* The sneak input * The sneak input
*/ */
SNEAK(mc.gameSettings.keyBindSneak); SNEAK(mc.gameSettings.keyBindSneak),
/**
* The sprint input
*/
SPRINT(mc.gameSettings.keyBindSprint);
/** /**
* The actual game {@link KeyBinding} being forced. * The actual game {@link KeyBinding} being forced.

View File

@ -19,8 +19,7 @@ package baritone.bot.pathing.movement;
import org.junit.Test; import org.junit.Test;
import static baritone.bot.pathing.movement.ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.FALL_N_BLOCKS_COST; import static baritone.bot.pathing.movement.ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.*;
import static baritone.bot.pathing.movement.ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.velocity;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
public class ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest { public class ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest {
@ -31,6 +30,9 @@ public class ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest {
double blocks = ticksToBlocks(FALL_N_BLOCKS_COST[i]); double blocks = ticksToBlocks(FALL_N_BLOCKS_COST[i]);
assertEquals(blocks, i, 0.000000000001); // If you add another 0 the test fails at i=217 LOL assertEquals(blocks, i, 0.000000000001); // If you add another 0 the test fails at i=217 LOL
} }
assertEquals(FALL_1_25_BLOCKS_COST, 6.2344, 0.00001);
assertEquals(FALL_0_25_BLOCKS_COST, 3.0710, 0.00001);
assertEquals(JUMP_ONE_BLOCK_COST, 3.1634, 0.00001);
} }
public double ticksToBlocks(double ticks) { public double ticksToBlocks(double ticks) {