1
0
mirror of https://github.com/cabaletta/baritone synced 2024-12-28 18:02:17 +00:00

Merge pull request #139 from cabaletta/parkour

Parkour
This commit is contained in:
Leijurv 2018-09-09 07:27:08 -07:00 committed by GitHub
commit 2533cbc2c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 2 deletions

View File

@ -9,6 +9,7 @@
- **Slabs and stairs**
- **Falling blocks** Baritone understands the costs of breaking blocks with falling blocks on top, and includes all of their break costs. Additionally, since it avoids breaking any blocks touching a liquid, it won't break the bottom of a gravel stack below a lava lake (anymore).
- **Avoiding dangerous blocks** Obviously, it knows not to walk through fire or on magma, not to corner over lava (that deals some damage), not to break any blocks touching a liquid (it might drown), etc.
- **Parkour** Sprint jumping over 1, 2, or 3 block gaps
# Pathing method
Baritone uses a modified version of A*.
@ -42,7 +43,7 @@ Things it doesn't have yet
See <a href="https://github.com/cabaletta/baritone/issues">issues</a> for more.
Things it may not ever have, from most likely to least likely =(
- Boats
- Pigs
- Boats
- Horses (2x3 path instead of 1x2)
- Elytra

View File

@ -83,6 +83,13 @@ public class Settings {
*/
public Setting<Boolean> allowWalkOnBottomSlab = new Setting<>(true);
/**
* You know what it is
* <p>
* But it's very unreliable and falls off when cornering like all the time so.
*/
public Setting<Boolean> allowParkour = new Setting<>(false);
/**
* For example, if you have Mining Fatigue or Haste, adjust the costs of breaking blocks accordingly.
*/

View File

@ -233,7 +233,11 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
new MovementDiagonal(pos, EnumFacing.NORTH, EnumFacing.EAST),
new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.WEST),
new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.EAST),
new MovementPillar(pos, new BetterBlockPos(x, y + 1, z))
new MovementPillar(pos, new BetterBlockPos(x, y + 1, z)),
MovementParkour.calculate(pos, EnumFacing.NORTH),
MovementParkour.calculate(pos, EnumFacing.SOUTH),
MovementParkour.calculate(pos, EnumFacing.EAST),
MovementParkour.calculate(pos, EnumFacing.WEST),
};
}

View File

@ -85,6 +85,10 @@ public abstract class Movement implements Helper, MovementHelper {
return getCost(null);
}
protected void override(double cost) {
this.cost = cost;
}
public double calculateCostWithoutCaching() {
return calculateCost(new CalculationContext());
}

View File

@ -70,6 +70,9 @@ public interface MovementHelper extends ActionCosts, Helper {
static boolean canWalkThrough(BlockPos pos, IBlockState state) {
Block block = state.getBlock();
if (block == Blocks.AIR) {
return true;
}
if (block instanceof BlockFire || block instanceof BlockTripWire || block instanceof BlockWeb || block instanceof BlockEndPortal) {
return false;
}
@ -103,6 +106,38 @@ public interface MovementHelper extends ActionCosts, Helper {
return block.isPassable(mc.world, pos);
}
/**
* 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)
*
* @return
*/
static boolean fullyPassable(BlockPos pos) {
return fullyPassable(pos, BlockStateInterface.get(pos));
}
static boolean fullyPassable(BlockPos pos, IBlockState state) {
Block block = state.getBlock();
if (block == Blocks.AIR) {
return true;
}
// exceptions - blocks that are isPassasble true, but we can't actually jump through
if (block == Blocks.FIRE
|| block == Blocks.TRIPWIRE
|| block == Blocks.WEB
|| block == Blocks.VINE
|| block == Blocks.LADDER
|| block instanceof BlockDoor
|| block instanceof BlockFenceGate
|| block instanceof BlockSnow
|| block instanceof BlockLiquid
|| block instanceof BlockTrapDoor
|| block instanceof BlockEndPortal) {
return false;
}
return block.isPassable(mc.world, pos);
}
static boolean isReplacable(BlockPos pos, IBlockState state) {
// for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case

View File

@ -0,0 +1,150 @@
/*
* 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,
* 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/>.
*/
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
public class MovementParkour extends Movement {
final EnumFacing direction;
final int dist;
private MovementParkour(BlockPos src, int dist, EnumFacing dir) {
super(src, src.offset(dir, dist), new BlockPos[]{});
this.direction = dir;
this.dist = dist;
super.override(costFromJumpDistance(dist));
}
public static MovementParkour calculate(BlockPos src, EnumFacing dir) {
if (!Baritone.settings().allowParkour.get()) {
return null;
}
IBlockState standingOn = BlockStateInterface.get(src.down());
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) {
return null;
}
BlockPos adjBlock = src.down().offset(dir);
IBlockState adj = BlockStateInterface.get(adjBlock);
if (MovementHelper.avoidWalkingInto(adj.getBlock())) { // magma sucks
return null;
}
if (MovementHelper.canWalkOn(adjBlock, adj)) { // don't parkour if we could just traverse (for now)
return null;
}
if (!MovementHelper.fullyPassable(src.offset(dir))) {
return null;
}
if (!MovementHelper.fullyPassable(src.up().offset(dir))) {
return null;
}
for (int i = 2; i <= 4; i++) {
BlockPos dest = src.offset(dir, i);
// TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly?
for (int y = 0; y < 4; y++) {
if (!MovementHelper.fullyPassable(dest.up(y))) {
return null;
}
}
if (MovementHelper.canWalkOn(dest.down())) {
return new MovementParkour(src, i, dir);
}
}
return null;
}
private static double costFromJumpDistance(int dist) {
switch (dist) {
case 2:
return WALK_ONE_BLOCK_COST * 2; // IDK LOL
case 3:
return WALK_ONE_BLOCK_COST * 3;
case 4:
return SPRINT_ONE_BLOCK_COST * 4;
}
throw new IllegalStateException("LOL");
}
@Override
protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(dest.down())) {
return COST_INF;
}
if (MovementHelper.avoidWalkingInto(BlockStateInterface.get(src.down().offset(direction)).getBlock())) {
return COST_INF;
}
for (int i = 1; i <= 4; i++) {
BlockPos d = src.offset(direction, i);
for (int y = 0; y < 4; y++) {
if (!MovementHelper.fullyPassable(d.up(y))) {
return COST_INF;
}
}
if (d.equals(dest)) {
return costFromJumpDistance(i);
}
}
throw new IllegalStateException("invalid jump distance?");
}
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
switch (state.getStatus()) {
case WAITING:
state.setStatus(MovementState.MovementStatus.RUNNING);
case RUNNING:
break;
default:
return state;
}
if (dist >= 4) {
state.setInput(InputOverrideHandler.Input.SPRINT, true);
}
MovementHelper.moveTowards(state, dest);
if (playerFeet().equals(dest)) {
if (player().posY - playerFeet().getY() < 0.01) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
}
} else if (!playerFeet().equals(src)) {
if (playerFeet().equals(src.offset(direction)) || player().posY - playerFeet().getY() > 0.0001) {
state.setInput(InputOverrideHandler.Input.JUMP, true);
} else {
state.setInput(InputOverrideHandler.Input.SPRINT, false);
if (playerFeet().equals(src.offset(direction, -1))) {
MovementHelper.moveTowards(state, src);
} else {
MovementHelper.moveTowards(state, src.offset(direction, -1));
}
}
}
return state;
}
}

View File

@ -119,4 +119,10 @@ public final class BetterBlockPos extends BlockPos {
Vec3i vec = dir.getDirectionVec();
return new BetterBlockPos(x + vec.getX(), y + vec.getY(), z + vec.getZ());
}
@Override
public BlockPos offset(EnumFacing dir, int dist) {
Vec3i vec = dir.getDirectionVec();
return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist);
}
}