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 .
*
2018-08-08 04:15:22 +00:00
* 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-05 05:15:18 +00:00
package baritone.bot.behavior.impl ;
2018-08-05 03:19:32 +00:00
2018-08-07 04:07:15 +00:00
import baritone.bot.Baritone ;
2018-08-05 05:15:18 +00:00
import baritone.bot.behavior.Behavior ;
2018-08-05 22:38:11 +00:00
import baritone.bot.event.events.ChatEvent ;
2018-08-05 21:48:10 +00:00
import baritone.bot.event.events.RenderEvent ;
2018-08-05 23:57:50 +00:00
import baritone.bot.event.events.TickEvent ;
2018-08-05 22:38:11 +00:00
import baritone.bot.pathing.calc.AStarPathFinder ;
2018-08-05 22:53:11 +00:00
import baritone.bot.pathing.calc.AbstractNodeCostSearch ;
2018-08-05 22:38:11 +00:00
import baritone.bot.pathing.calc.IPathFinder ;
import baritone.bot.pathing.goals.Goal ;
import baritone.bot.pathing.goals.GoalBlock ;
2018-08-07 14:47:37 +00:00
import baritone.bot.pathing.goals.GoalXZ ;
2018-08-10 17:45:18 +00:00
import baritone.bot.pathing.goals.GoalYLevel ;
2018-08-05 03:28:32 +00:00
import baritone.bot.pathing.path.IPath ;
2018-08-05 03:25:05 +00:00
import baritone.bot.pathing.path.PathExecutor ;
2018-08-09 21:48:10 +00:00
import baritone.bot.utils.PathRenderer ;
2018-08-05 22:38:11 +00:00
import net.minecraft.util.math.BlockPos ;
import java.awt.* ;
2018-08-09 23:37:08 +00:00
import java.util.Arrays ;
2018-08-06 07:21:47 +00:00
import java.util.Optional ;
2018-08-05 03:25:05 +00:00
2018-08-05 03:28:32 +00:00
public class PathingBehavior extends Behavior {
2018-08-05 05:25:08 +00:00
2018-08-05 03:28:32 +00:00
public static final PathingBehavior INSTANCE = new PathingBehavior ( ) ;
2018-08-05 05:25:08 +00:00
private PathingBehavior ( ) { }
2018-08-05 03:25:05 +00:00
private PathExecutor current ;
2018-08-13 18:49:36 +00:00
private PathExecutor next ;
2018-08-05 03:25:05 +00:00
2018-08-05 22:38:11 +00:00
private Goal goal ;
2018-08-13 19:35:44 +00:00
private volatile boolean isPathCalcInProgress ;
private final Object pathCalcLock = new Object ( ) ;
private final Object pathPlanLock = new Object ( ) ;
2018-08-05 03:28:32 +00:00
@Override
2018-08-05 23:57:50 +00:00
public void onTick ( TickEvent event ) {
2018-08-06 22:53:35 +00:00
if ( event . getType ( ) = = TickEvent . Type . OUT | | current = = null ) {
2018-08-05 03:28:32 +00:00
return ;
}
2018-08-13 19:35:44 +00:00
boolean safe = current . onTick ( event ) ;
synchronized ( pathPlanLock ) {
if ( current . failed ( ) | | current . finished ( ) ) {
current = null ;
2018-08-13 19:56:08 +00:00
if ( goal . isInGoal ( playerFeet ( ) ) ) {
displayChatMessageRaw ( " All done. At " + goal ) ;
next = null ;
return ;
}
2018-08-13 19:35:44 +00:00
if ( next ! = null & & ! next . getPath ( ) . positions ( ) . contains ( playerFeet ( ) ) ) {
// if the current path failed, we may not actually be on the next one, so make sure
displayChatMessageRaw ( " Discarding next path as it does not contain current position " ) ;
// for example if we had a nicely planned ahead path that starts where current ends
// that's all fine and good
// but if we fail in the middle of current
// we're nowhere close to our planned ahead path
// so need to discard it sadly.
next = null ;
}
if ( next ! = null ) {
2018-08-13 20:00:57 +00:00
displayChatMessageRaw ( " Continuing on to planned next path " ) ;
2018-08-13 19:35:44 +00:00
current = next ;
next = null ;
return ;
}
// at this point, current just ended, but we aren't in the goal and have no plan for the future
synchronized ( pathCalcLock ) {
if ( isPathCalcInProgress ) {
// if we aren't calculating right now
return ;
}
findPathInNewThread ( playerFeet ( ) , true ) ;
}
return ;
}
// at this point, we know current is in progress
if ( safe ) {
// a movement just ended
if ( next ! = null ) {
if ( next . getPath ( ) . positions ( ) . contains ( playerFeet ( ) ) ) {
// jump directly onto the next path
2018-08-13 20:00:57 +00:00
displayChatMessageRaw ( " Splicing into planned next path early... " ) ;
2018-08-13 19:35:44 +00:00
current = next ;
next = null ;
return ;
}
}
}
synchronized ( pathCalcLock ) {
if ( isPathCalcInProgress ) {
// if we aren't calculating right now
return ;
}
if ( next ! = null ) {
// and we have no plan for what to do next
return ;
}
if ( goal . isInGoal ( current . getPath ( ) . getDest ( ) ) ) {
// and this path dosen't get us all the way there
return ;
}
2018-08-13 19:42:28 +00:00
if ( current . getPath ( ) . ticksRemainingFrom ( current . getPosition ( ) ) < 200 ) {
2018-08-13 19:35:44 +00:00
// and this path has 5 seconds or less left
2018-08-13 19:56:08 +00:00
displayChatMessageRaw ( " Path almost over. Planning ahead... " ) ;
2018-08-13 19:42:28 +00:00
findPathInNewThread ( current . getPath ( ) . getDest ( ) , false ) ;
2018-08-13 19:35:44 +00:00
}
}
2018-08-05 03:28:32 +00:00
}
}
2018-08-05 22:38:11 +00:00
@Override
public void onSendChatMessage ( ChatEvent event ) {
String msg = event . getMessage ( ) ;
2018-08-10 17:45:18 +00:00
if ( msg . toLowerCase ( ) . startsWith ( " goal " ) ) {
2018-08-05 22:38:11 +00:00
event . cancel ( ) ;
2018-08-10 17:45:18 +00:00
String [ ] params = msg . toLowerCase ( ) . substring ( 4 ) . trim ( ) . split ( " " ) ;
2018-08-12 00:13:12 +00:00
if ( params [ 0 ] . equals ( " " ) ) {
params = new String [ ] { } ;
}
2018-08-10 17:45:18 +00:00
try {
switch ( params . length ) {
case 0 :
goal = new GoalBlock ( playerFeet ( ) ) ;
break ;
case 1 :
goal = new GoalYLevel ( Integer . parseInt ( params [ 0 ] ) ) ;
break ;
case 2 :
goal = new GoalXZ ( Integer . parseInt ( params [ 0 ] ) , Integer . parseInt ( params [ 1 ] ) ) ;
break ;
case 3 :
goal = new GoalBlock ( new BlockPos ( Integer . parseInt ( params [ 0 ] ) , Integer . parseInt ( params [ 1 ] ) , Integer . parseInt ( params [ 2 ] ) ) ) ;
break ;
default :
displayChatMessageRaw ( " unable to understand lol " ) ;
return ;
}
} catch ( NumberFormatException ex ) {
displayChatMessageRaw ( " unable to parse integer " + ex ) ;
return ;
}
displayChatMessageRaw ( " Goal: " + goal ) ;
2018-08-05 22:38:11 +00:00
return ;
}
if ( msg . equals ( " path " ) ) {
findPathInNewThread ( playerFeet ( ) , true ) ;
event . cancel ( ) ;
return ;
}
2018-08-06 14:01:25 +00:00
if ( msg . toLowerCase ( ) . equals ( " slowpath " ) ) {
AStarPathFinder . slowPath ^ = true ;
event . cancel ( ) ;
return ;
}
2018-08-07 04:07:15 +00:00
if ( msg . toLowerCase ( ) . equals ( " cancel " ) ) {
current = null ;
Baritone . INSTANCE . getInputOverrideHandler ( ) . clearAllKeys ( ) ;
event . cancel ( ) ;
displayChatMessageRaw ( " ok canceled " ) ;
return ;
}
2018-08-07 14:47:37 +00:00
if ( msg . toLowerCase ( ) . startsWith ( " thisway " ) ) {
2018-08-09 21:35:42 +00:00
goal = GoalXZ . fromDirection ( playerFeetAsVec ( ) , player ( ) . rotationYaw , Double . parseDouble ( msg . substring ( 7 ) . trim ( ) ) ) ;
2018-08-07 14:47:37 +00:00
displayChatMessageRaw ( " Goal: " + goal ) ;
event . cancel ( ) ;
return ;
}
}
2018-08-05 22:38:11 +00:00
2018-08-09 21:48:10 +00:00
public PathExecutor getExecutor ( ) {
return current ;
}
public Optional < IPath > getPath ( ) {
return Optional . ofNullable ( current ) . map ( PathExecutor : : getPath ) ;
2018-08-05 22:38:11 +00:00
}
/ * *
* In a new thread , pathfind to target blockpos
*
* @param start
* @param talkAboutIt
* /
public void findPathInNewThread ( final BlockPos start , final boolean talkAboutIt ) {
2018-08-13 19:35:44 +00:00
synchronized ( pathCalcLock ) {
if ( isPathCalcInProgress ) {
throw new IllegalStateException ( " Already doing it " ) ;
}
isPathCalcInProgress = true ;
}
2018-08-05 23:56:21 +00:00
new Thread ( ( ) - > {
if ( talkAboutIt ) {
displayChatMessageRaw ( " Starting to search for path from " + start + " to " + goal ) ;
}
2018-08-05 22:38:11 +00:00
2018-08-13 19:56:08 +00:00
findPath ( start ) . map ( IPath : : cutoffAtLoadedChunks ) . map ( PathExecutor : : new ) . ifPresent ( path - > {
2018-08-13 19:35:44 +00:00
synchronized ( pathPlanLock ) {
if ( current = = null ) {
current = path ;
} else {
if ( next = = null ) {
next = path ;
} else {
throw new IllegalStateException ( " I have no idea what to do with this path " ) ;
}
}
}
} ) ;
2018-08-09 21:48:10 +00:00
/ *
isThereAnythingInProgress = false ;
2018-08-05 23:56:21 +00:00
if ( ! currentPath . goal . isInGoal ( currentPath . end ) ) {
if ( talkAboutIt ) {
Out . gui ( " I couldn't get all the way to " + goal + " , but I'm going to get as close as I can. " + currentPath . numNodes + " nodes considered " , Out . Mode . Standard ) ;
2018-08-05 22:38:11 +00:00
}
2018-08-05 23:56:21 +00:00
planAhead ( ) ;
} else if ( talkAboutIt ) {
2018-08-06 14:14:20 +00:00
Out . gui ( , Out . Mode . Debug ) ;
2018-08-09 21:48:10 +00:00
}
* /
2018-08-06 14:14:20 +00:00
if ( talkAboutIt & & current ! = null & & current . getPath ( ) ! = null ) {
2018-08-10 17:45:18 +00:00
displayChatMessageRaw ( " Finished finding a path from " + start + " towards " + goal + " . " + current . getPath ( ) . getNumNodesConsidered ( ) + " nodes considered " ) ;
2018-08-06 14:14:20 +00:00
}
2018-08-13 19:35:44 +00:00
synchronized ( pathCalcLock ) {
isPathCalcInProgress = false ;
}
2018-08-05 23:56:21 +00:00
} ) . start ( ) ;
2018-08-05 22:38:11 +00:00
}
/ * *
* Actually do the pathing
*
* @param start
* @return
* /
2018-08-06 07:21:47 +00:00
private Optional < IPath > findPath ( BlockPos start ) {
2018-08-05 22:38:11 +00:00
if ( goal = = null ) {
2018-08-05 23:56:21 +00:00
displayChatMessageRaw ( " no goal " ) ;
2018-08-06 07:21:47 +00:00
return Optional . empty ( ) ;
2018-08-05 22:38:11 +00:00
}
try {
IPathFinder pf = new AStarPathFinder ( start , goal ) ;
2018-08-06 07:21:47 +00:00
return pf . calculate ( ) ;
2018-08-05 22:38:11 +00:00
} catch ( Exception e ) {
e . printStackTrace ( ) ;
2018-08-06 07:21:47 +00:00
return Optional . empty ( ) ;
2018-08-05 22:38:11 +00:00
}
}
2018-08-05 21:48:10 +00:00
@Override
public void onRenderPass ( RenderEvent event ) {
2018-08-09 21:48:10 +00:00
// System.out.println("Render passing");
// System.out.println(event.getPartialTicks());
2018-08-05 22:53:11 +00:00
float partialTicks = event . getPartialTicks ( ) ;
2018-08-09 23:37:08 +00:00
long start = System . nanoTime ( ) ;
2018-08-06 07:21:47 +00:00
// Render the current path, if there is one
2018-08-09 20:08:56 +00:00
if ( current ! = null & & current . getPath ( ) ! = null ) {
int renderBegin = Math . max ( current . getPosition ( ) - 3 , 0 ) ;
2018-08-09 21:48:10 +00:00
PathRenderer . drawPath ( current . getPath ( ) , renderBegin , player ( ) , partialTicks , Color . RED ) ;
2018-08-09 20:08:56 +00:00
}
2018-08-13 19:57:21 +00:00
if ( next ! = null & & next . getPath ( ) ! = null ) {
PathRenderer . drawPath ( next . getPath ( ) , 0 , player ( ) , partialTicks , Color . GREEN ) ;
}
2018-08-09 23:44:41 +00:00
2018-08-09 23:37:08 +00:00
long split = System . nanoTime ( ) ;
if ( current ! = null ) {
2018-08-09 23:44:41 +00:00
PathRenderer . drawManySelectionBoxes ( player ( ) , current . toBreak ( ) , partialTicks , Color . RED ) ;
PathRenderer . drawManySelectionBoxes ( player ( ) , current . toPlace ( ) , partialTicks , Color . GREEN ) ;
2018-08-12 15:40:44 +00:00
PathRenderer . drawManySelectionBoxes ( player ( ) , current . toWalkInto ( ) , partialTicks , Color . MAGENTA ) ;
2018-08-09 23:37:08 +00:00
}
2018-08-06 07:21:47 +00:00
// If there is a path calculation currently running, render the path calculation process
AbstractNodeCostSearch . getCurrentlyRunning ( ) . ifPresent ( currentlyRunning - > {
currentlyRunning . bestPathSoFar ( ) . ifPresent ( p - > {
2018-08-09 21:48:10 +00:00
PathRenderer . drawPath ( p , 0 , player ( ) , partialTicks , Color . BLUE ) ;
2018-08-06 07:21:47 +00:00
currentlyRunning . pathToMostRecentNodeConsidered ( ) . ifPresent ( mr - > {
2018-08-09 23:44:41 +00:00
2018-08-09 21:48:10 +00:00
PathRenderer . drawPath ( mr , 0 , player ( ) , partialTicks , Color . CYAN ) ;
2018-08-09 23:44:41 +00:00
PathRenderer . drawManySelectionBoxes ( player ( ) , Arrays . asList ( mr . getDest ( ) ) , partialTicks , Color . CYAN ) ;
2018-08-06 07:21:47 +00:00
} ) ;
} ) ;
} ) ;
2018-08-09 23:37:08 +00:00
long end = System . nanoTime ( ) ;
//System.out.println((end - split) + " " + (split - start));
2018-08-07 02:48:09 +00:00
// if (end - start > 0)
// System.out.println("Frame took " + (split - start) + " " + (end - split));
2018-08-09 23:37:08 +00:00
2018-08-05 22:53:11 +00:00
}
2018-08-05 03:19:32 +00:00
}