2018-09-06 14:48:27 +00:00
/ *
* This file is part of Baritone .
*
* Baritone is free software : you can redistribute it and / or modify
2018-09-17 22:11:40 +00:00
* it under the terms of the GNU Lesser General Public License as published by
2018-09-06 14:48:27 +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 ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
2018-09-17 22:11:40 +00:00
* GNU Lesser General Public License for more details .
2018-09-06 14:48:27 +00:00
*
2018-09-17 22:11:40 +00:00
* You should have received a copy of the GNU Lesser General Public License
2018-09-06 14:48:27 +00:00
* along with Baritone . If not , see < https : //www.gnu.org/licenses/>.
* /
package baritone.pathing.movement.movements ;
2018-11-13 17:50:29 +00:00
import baritone.api.IBaritone ;
2018-10-09 01:37:52 +00:00
import baritone.api.pathing.movement.MovementStatus ;
import baritone.api.utils.BetterBlockPos ;
2018-11-13 17:50:29 +00:00
import baritone.api.utils.input.Input ;
2018-10-09 01:37:52 +00:00
import baritone.pathing.movement.CalculationContext ;
import baritone.pathing.movement.Movement ;
import baritone.pathing.movement.MovementHelper ;
import baritone.pathing.movement.MovementState ;
2018-11-11 20:35:04 +00:00
import baritone.utils.BlockStateInterface ;
2018-10-05 19:24:52 +00:00
import baritone.utils.pathing.MutableMoveResult ;
2018-10-02 22:34:46 +00:00
import net.minecraft.block.Block ;
2019-02-24 21:57:33 +00:00
import net.minecraft.block.BlockLiquid ;
2018-11-23 15:47:28 +00:00
import net.minecraft.block.BlockStairs ;
2018-09-06 14:48:27 +00:00
import net.minecraft.block.state.IBlockState ;
import net.minecraft.init.Blocks ;
import net.minecraft.util.EnumFacing ;
2018-09-12 03:09:53 +00:00
2019-06-25 00:53:25 +00:00
import java.util.HashSet ;
import java.util.Set ;
2018-09-06 14:48:27 +00:00
public class MovementParkour extends Movement {
2018-09-23 20:26:57 +00:00
2018-09-22 15:47:02 +00:00
private static final BetterBlockPos [ ] EMPTY = new BetterBlockPos [ ] { } ;
2018-09-12 03:09:53 +00:00
2018-09-17 00:49:19 +00:00
private final EnumFacing direction ;
private final int dist ;
2019-07-31 04:07:26 +00:00
private final boolean ascend ;
2018-09-06 14:48:27 +00:00
2019-07-31 04:07:26 +00:00
private MovementParkour ( IBaritone baritone , BetterBlockPos src , int dist , EnumFacing dir , boolean ascend ) {
super ( baritone , src , src . offset ( dir , dist ) . up ( ascend ? 1 : 0 ) , EMPTY , src . offset ( dir , dist ) . down ( ascend ? 0 : 1 ) ) ;
2018-09-06 14:48:27 +00:00
this . direction = dir ;
this . dist = dist ;
2019-07-31 04:07:26 +00:00
this . ascend = ascend ;
2018-09-06 14:48:27 +00:00
}
2018-11-23 17:00:52 +00:00
public static MovementParkour cost ( CalculationContext context , BetterBlockPos src , EnumFacing direction ) {
2018-10-05 19:24:52 +00:00
MutableMoveResult res = new MutableMoveResult ( ) ;
2018-11-23 17:00:52 +00:00
cost ( context , src . x , src . y , src . z , direction , res ) ;
2018-10-05 19:24:52 +00:00
int dist = Math . abs ( res . x - src . x ) + Math . abs ( res . z - src . z ) ;
2019-07-31 04:37:50 +00:00
return new MovementParkour ( context . getBaritone ( ) , src , dist , direction , res . y > src . y ) ;
2018-09-23 19:24:07 +00:00
}
2018-10-05 19:24:52 +00:00
public static void cost ( CalculationContext context , int x , int y , int z , EnumFacing dir , MutableMoveResult res ) {
2018-12-21 05:22:18 +00:00
if ( ! context . allowParkour ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2018-12-21 05:22:18 +00:00
if ( y = = 256 & & ! context . allowJumpAt256 ) {
2018-12-13 02:14:56 +00:00
return ;
}
2018-12-04 22:38:08 +00:00
2018-09-23 19:24:07 +00:00
int xDiff = dir . getXOffset ( ) ;
int zDiff = dir . getZOffset ( ) ;
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , x + xDiff , y , z + zDiff ) ) {
2018-12-04 22:38:08 +00:00
// most common case at the top -- the adjacent block isn't air
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2018-12-04 22:38:08 +00:00
IBlockState adj = context . get ( x + xDiff , y - 1 , z + zDiff ) ;
2018-12-21 05:22:18 +00:00
if ( MovementHelper . canWalkOn ( context . bsi , x + xDiff , y - 1 , z + zDiff , adj ) ) { // don't parkour if we could just traverse (for now)
2018-12-04 22:38:08 +00:00
// second most common case -- we could just traverse not parkour
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2018-12-04 22:38:08 +00:00
if ( MovementHelper . avoidWalkingInto ( adj . getBlock ( ) ) & & adj . getBlock ( ) ! = Blocks . WATER & & adj . getBlock ( ) ! = Blocks . FLOWING_WATER ) { // magma sucks
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , x + xDiff , y + 1 , z + zDiff ) ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , x + xDiff , y + 2 , z + zDiff ) ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-10 16:22:32 +00:00
}
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , x , y + 2 , z ) ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-10 16:22:32 +00:00
}
2018-12-04 22:38:08 +00:00
IBlockState standingOn = context . get ( x , y - 1 , z ) ;
2019-02-24 21:57:33 +00:00
if ( standingOn . getBlock ( ) = = Blocks . VINE | | standingOn . getBlock ( ) = = Blocks . LADDER | | standingOn . getBlock ( ) instanceof BlockStairs | | MovementHelper . isBottomSlab ( standingOn ) | | standingOn . getBlock ( ) instanceof BlockLiquid ) {
2018-12-04 22:38:08 +00:00
return ;
}
2018-11-05 21:47:00 +00:00
int maxJump ;
if ( standingOn . getBlock ( ) = = Blocks . SOUL_SAND ) {
maxJump = 2 ; // 1 block gap
} else {
2018-12-21 05:22:18 +00:00
if ( context . canSprint ) {
2018-11-05 21:47:00 +00:00
maxJump = 4 ;
} else {
maxJump = 3 ;
}
}
for ( int i = 2 ; i < = maxJump ; i + + ) {
2019-07-31 04:07:26 +00:00
int destX = x + xDiff * i ;
int destZ = z + zDiff * i ;
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , destX , y + 1 , destZ ) ) {
2019-07-31 04:07:26 +00:00
return ;
}
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , destX , y + 2 , destZ ) ) {
2019-07-31 04:07:26 +00:00
return ;
}
2019-08-01 03:47:46 +00:00
IBlockState destInto = context . bsi . get0 ( destX , y , destZ ) ;
2019-11-06 00:17:10 +00:00
if ( ! MovementHelper . fullyPassable ( context . bsi . access , context . bsi . isPassableBlockPos . setPos ( destX , y , destZ ) , destInto ) ) {
2019-08-01 03:47:46 +00:00
if ( i < = 3 & & context . allowParkourAscend & & context . canSprint & & MovementHelper . canWalkOn ( context . bsi , destX , y , destZ , destInto ) & & checkOvershootSafety ( context . bsi , destX + xDiff , y + 1 , destZ + zDiff ) ) {
2019-07-31 04:07:26 +00:00
res . x = destX ;
res . y = y + 1 ;
res . z = destZ ;
2019-07-31 04:37:50 +00:00
res . cost = i * SPRINT_ONE_BLOCK_COST + context . jumpPenalty ;
2018-09-06 17:13:50 +00:00
}
2019-07-31 04:07:26 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
2019-07-31 04:07:26 +00:00
IBlockState landingOn = context . bsi . get0 ( destX , y - 1 , destZ ) ;
2019-04-14 02:05:54 +00:00
// farmland needs to be canwalkon otherwise farm can never work at all, but we want to specifically disallow ending a jumy on farmland haha
2019-07-31 04:07:26 +00:00
if ( landingOn . getBlock ( ) ! = Blocks . FARMLAND & & MovementHelper . canWalkOn ( context . bsi , destX , y - 1 , destZ , landingOn ) ) {
if ( checkOvershootSafety ( context . bsi , destX + xDiff , y , destZ + zDiff ) ) {
res . x = destX ;
res . y = y ;
res . z = destZ ;
res . cost = costFromJumpDistance ( i ) + context . jumpPenalty ;
}
return ;
}
2019-10-24 20:20:23 +00:00
if ( ! MovementHelper . fullyPassable ( context , destX , y + 3 , destZ ) ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-06 14:48:27 +00:00
}
}
2018-11-05 21:47:00 +00:00
if ( maxJump ! = 4 ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-14 15:40:34 +00:00
}
2018-12-21 05:22:18 +00:00
if ( ! context . allowParkourPlace ) {
2018-10-05 19:24:52 +00:00
return ;
2018-10-04 02:00:58 +00:00
}
2018-12-26 05:07:17 +00:00
// time 2 pop off with that dank skynet parkour place
2018-09-23 19:24:07 +00:00
int destX = x + 4 * xDiff ;
int destZ = z + 4 * zDiff ;
2019-10-07 00:32:25 +00:00
IBlockState toReplace = context . get ( destX , y - 1 , destZ ) ;
double placeCost = context . costOfPlacingAt ( destX , y - 1 , destZ , toReplace ) ;
2018-12-26 05:07:17 +00:00
if ( placeCost > = COST_INF ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-12 03:09:53 +00:00
}
2019-09-06 10:59:10 +00:00
if ( ! MovementHelper . isReplaceable ( destX , y - 1 , destZ , toReplace , context . bsi ) ) {
2018-10-05 19:24:52 +00:00
return ;
2018-09-12 03:09:53 +00:00
}
2019-07-31 04:07:26 +00:00
if ( ! checkOvershootSafety ( context . bsi , destX + xDiff , y , destZ + zDiff ) ) {
return ;
}
2018-09-12 03:09:53 +00:00
for ( int i = 0 ; i < 5 ; i + + ) {
2019-06-06 05:12:28 +00:00
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP [ i ] . getXOffset ( ) ;
int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP [ i ] . getYOffset ( ) ;
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP [ i ] . getZOffset ( ) ;
2018-09-23 19:24:07 +00:00
if ( againstX = = x + xDiff * 3 & & againstZ = = z + zDiff * 3 ) { // we can't turn around that fast
2018-09-12 03:09:53 +00:00
continue ;
}
2018-12-21 05:22:18 +00:00
if ( MovementHelper . canPlaceAgainst ( context . bsi , againstX , againstY , againstZ ) ) {
2018-10-05 19:24:52 +00:00
res . x = destX ;
res . y = y ;
res . z = destZ ;
2018-12-26 05:07:17 +00:00
res . cost = costFromJumpDistance ( 4 ) + placeCost + context . jumpPenalty ;
2018-10-05 19:24:52 +00:00
return ;
2018-09-12 03:09:53 +00:00
}
}
2018-09-06 14:48:27 +00:00
}
2019-07-31 04:07:26 +00:00
private static boolean checkOvershootSafety ( BlockStateInterface bsi , int x , int y , int z ) {
// we're going to walk into these two blocks after the landing of the parkour anyway, so make sure they aren't avoidWalkingInto
return ! MovementHelper . avoidWalkingInto ( bsi . get0 ( x , y , z ) . getBlock ( ) ) & & ! MovementHelper . avoidWalkingInto ( bsi . get0 ( x , y + 1 , z ) . getBlock ( ) ) ;
}
2018-09-06 14:48:27 +00:00
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 :
2018-09-06 14:54:12 +00:00
return SPRINT_ONE_BLOCK_COST * 4 ;
2018-09-17 02:50:07 +00:00
default :
2018-10-02 02:23:13 +00:00
throw new IllegalStateException ( " LOL " + dist ) ;
2018-09-06 14:48:27 +00:00
}
}
@Override
2019-01-08 22:56:21 +00:00
public double calculateCost ( CalculationContext context ) {
2018-10-05 19:24:52 +00:00
MutableMoveResult res = new MutableMoveResult ( ) ;
cost ( context , src . x , src . y , src . z , direction , res ) ;
2019-08-01 05:17:44 +00:00
if ( res . x ! = dest . x | | res . y ! = dest . y | | res . z ! = dest . z ) {
2018-09-06 14:48:27 +00:00
return COST_INF ;
}
2018-09-23 20:26:57 +00:00
return res . cost ;
2018-09-06 14:48:27 +00:00
}
2019-06-25 00:53:25 +00:00
@Override
protected Set < BetterBlockPos > calculateValidPositions ( ) {
Set < BetterBlockPos > set = new HashSet < > ( ) ;
for ( int i = 0 ; i < = dist ; i + + ) {
for ( int y = 0 ; y < 2 ; y + + ) {
set . add ( src . offset ( direction , i ) . up ( y ) ) ;
}
}
return set ;
}
2018-10-07 01:39:30 +00:00
@Override
public boolean safeToCancel ( MovementState state ) {
// once this movement is instantiated, the state is default to PREPPING
// but once it's ticked for the first time it changes to RUNNING
// since we don't really know anything about momentum, it suffices to say Parkour can only be canceled on the 0th tick
2018-10-09 00:57:22 +00:00
return state . getStatus ( ) ! = MovementStatus . RUNNING ;
2018-10-07 01:39:30 +00:00
}
2018-09-06 14:48:27 +00:00
@Override
public MovementState updateState ( MovementState state ) {
super . updateState ( state ) ;
2018-10-09 00:57:22 +00:00
if ( state . getStatus ( ) ! = MovementStatus . RUNNING ) {
2018-09-14 22:57:46 +00:00
return state ;
2018-09-06 14:48:27 +00:00
}
2019-02-04 21:52:11 +00:00
if ( ctx . playerFeet ( ) . y < src . y ) {
// we have fallen
logDebug ( " sorry " ) ;
return state . setStatus ( MovementStatus . UNREACHABLE ) ;
}
2019-07-31 04:07:26 +00:00
if ( dist > = 4 | | ascend ) {
2018-11-13 17:50:29 +00:00
state . setInput ( Input . SPRINT , true ) ;
2018-09-06 14:48:27 +00:00
}
2018-11-13 17:50:29 +00:00
MovementHelper . moveTowards ( ctx , state , dest ) ;
if ( ctx . playerFeet ( ) . equals ( dest ) ) {
2018-11-13 21:14:29 +00:00
Block d = BlockStateInterface . getBlock ( ctx , dest ) ;
2018-10-02 22:34:46 +00:00
if ( d = = Blocks . VINE | | d = = Blocks . LADDER ) {
// it physically hurt me to add support for parkour jumping onto a vine
// but i did it anyway
2018-10-09 00:57:22 +00:00
return state . setStatus ( MovementStatus . SUCCESS ) ;
2018-10-02 22:34:46 +00:00
}
2018-11-13 17:50:29 +00:00
if ( ctx . player ( ) . posY - ctx . playerFeet ( ) . getY ( ) < 0 . 094 ) { // lilypads
2018-10-09 00:57:22 +00:00
state . setStatus ( MovementStatus . SUCCESS ) ;
2018-09-06 14:48:27 +00:00
}
2018-11-13 17:50:29 +00:00
} else if ( ! ctx . playerFeet ( ) . equals ( src ) ) {
2019-07-11 19:46:24 +00:00
if ( ctx . playerFeet ( ) . equals ( src . offset ( direction ) ) | | ctx . player ( ) . posY - src . y > 0 . 0001 ) {
2019-01-13 03:51:21 +00:00
if ( ! MovementHelper . canWalkOn ( ctx , dest . down ( ) ) & & ! ctx . player ( ) . onGround & & MovementHelper . attemptToPlaceABlock ( state , baritone , dest . down ( ) , true ) = = PlaceResult . READY_TO_PLACE ) {
2019-01-11 01:23:20 +00:00
// go in the opposite order to check DOWN before all horizontals -- down is preferable because you don't have to look to the side while in midair, which could mess up the trajectory
state . setInput ( Input . CLICK_RIGHT , true ) ;
2018-09-12 03:09:53 +00:00
}
2019-07-31 04:37:50 +00:00
// prevent jumping too late by checking for ascend
2019-07-31 04:07:26 +00:00
if ( dist = = 3 & & ! ascend ) { // this is a 2 block gap, dest = src + direction * 3
2018-11-13 17:50:29 +00:00
double xDiff = ( src . x + 0 . 5 ) - ctx . player ( ) . posX ;
double zDiff = ( src . z + 0 . 5 ) - ctx . player ( ) . posZ ;
2018-10-14 00:01:00 +00:00
double distFromStart = Math . max ( Math . abs ( xDiff ) , Math . abs ( zDiff ) ) ;
if ( distFromStart < 0 . 7 ) {
return state ;
}
}
2018-09-12 03:09:53 +00:00
2018-11-13 17:50:29 +00:00
state . setInput ( Input . JUMP , true ) ;
} else if ( ! ctx . playerFeet ( ) . equals ( dest . offset ( direction , - 1 ) ) ) {
state . setInput ( Input . SPRINT , false ) ;
if ( ctx . playerFeet ( ) . equals ( src . offset ( direction , - 1 ) ) ) {
MovementHelper . moveTowards ( ctx , state , src ) ;
2018-09-06 14:48:27 +00:00
} else {
2018-11-13 17:50:29 +00:00
MovementHelper . moveTowards ( ctx , state , src . offset ( direction , - 1 ) ) ;
2018-09-06 14:48:27 +00:00
}
}
}
return state ;
}
2018-11-11 20:35:04 +00:00
}