baritone/src/main/java/baritone/bot/behavior/impl/PathingBehavior.java

311 lines
12 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 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,
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;
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;
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;
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
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(" ");
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
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");
}
}
}
});
/*
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-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
*/
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");
return Optional.empty();
2018-08-05 22:38:11 +00:00
}
try {
IPathFinder pf = new AStarPathFinder(start, goal);
return pf.calculate();
2018-08-05 22:38:11 +00:00
} catch (Exception e) {
e.printStackTrace();
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) {
// 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();
// Render the current path, if there is one
if (current != null && current.getPath() != null) {
int renderBegin = Math.max(current.getPosition() - 3, 0);
PathRenderer.drawPath(current.getPath(), renderBegin, player(), partialTicks, Color.RED);
}
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
}
// If there is a path calculation currently running, render the path calculation process
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
currentlyRunning.bestPathSoFar().ifPresent(p -> {
PathRenderer.drawPath(p, 0, player(), partialTicks, Color.BLUE);
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
2018-08-09 23:44:41 +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-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
}