mirror of https://github.com/cabaletta/baritone
200 lines
7.4 KiB
Java
200 lines
7.4 KiB
Java
/*
|
|
* This file is part of Baritone.
|
|
*
|
|
* Baritone is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package baritone.utils;
|
|
|
|
import baritone.Baritone;
|
|
import baritone.api.event.events.TickEvent;
|
|
import baritone.api.event.listener.AbstractGameEventListener;
|
|
import baritone.api.pathing.calc.IPathingControlManager;
|
|
import baritone.api.pathing.goals.Goal;
|
|
import baritone.api.process.IBaritoneProcess;
|
|
import baritone.api.process.PathingCommand;
|
|
import baritone.behavior.PathingBehavior;
|
|
import baritone.pathing.path.PathExecutor;
|
|
import net.minecraft.util.math.BlockPos;
|
|
|
|
import java.util.*;
|
|
import java.util.stream.Stream;
|
|
|
|
public class PathingControlManager implements IPathingControlManager {
|
|
private final Baritone baritone;
|
|
private final HashSet<IBaritoneProcess> processes; // unGh
|
|
private IBaritoneProcess inControlLastTick;
|
|
private IBaritoneProcess inControlThisTick;
|
|
private PathingCommand command;
|
|
|
|
public PathingControlManager(Baritone baritone) {
|
|
this.baritone = baritone;
|
|
this.processes = new HashSet<>();
|
|
baritone.getGameEventHandler().registerEventListener(new AbstractGameEventListener() { // needs to be after all behavior ticks
|
|
@Override
|
|
public void onTick(TickEvent event) {
|
|
if (event.getType() == TickEvent.Type.OUT) {
|
|
return;
|
|
}
|
|
postTick();
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void registerProcess(IBaritoneProcess process) {
|
|
process.onLostControl(); // make sure it's reset
|
|
processes.add(process);
|
|
}
|
|
|
|
public void cancelEverything() { // called by PathingBehavior on TickEvent Type OUT
|
|
inControlLastTick = null;
|
|
inControlThisTick = null;
|
|
command = null;
|
|
for (IBaritoneProcess proc : processes) {
|
|
proc.onLostControl();
|
|
if (proc.isActive() && !proc.isTemporary()) { // it's okay only for a temporary thing (like combat pause) to maintain control even if you say to cancel
|
|
throw new IllegalStateException(proc.displayName());
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Optional<IBaritoneProcess> mostRecentInControl() {
|
|
return Optional.ofNullable(inControlThisTick);
|
|
}
|
|
|
|
@Override
|
|
public Optional<PathingCommand> mostRecentCommand() {
|
|
return Optional.ofNullable(command);
|
|
}
|
|
|
|
public void preTick() {
|
|
inControlLastTick = inControlThisTick;
|
|
PathingBehavior p = baritone.getPathingBehavior();
|
|
command = executeProcesses();
|
|
if (command == null) {
|
|
p.cancelSegmentIfSafe();
|
|
return;
|
|
}
|
|
switch (command.commandType) {
|
|
case REQUEST_PAUSE:
|
|
p.requestPause();
|
|
break;
|
|
case CANCEL_AND_SET_GOAL:
|
|
p.secretInternalSetGoal(command.goal);
|
|
p.cancelSegmentIfSafe();
|
|
break;
|
|
case FORCE_REVALIDATE_GOAL_AND_PATH:
|
|
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
|
p.secretInternalSetGoalAndPath(command.goal);
|
|
}
|
|
break;
|
|
case REVALIDATE_GOAL_AND_PATH:
|
|
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
|
p.secretInternalSetGoalAndPath(command.goal);
|
|
}
|
|
break;
|
|
case SET_GOAL_AND_PATH:
|
|
// now this i can do
|
|
if (command.goal != null) {
|
|
baritone.getPathingBehavior().secretInternalSetGoalAndPath(command.goal);
|
|
}
|
|
break;
|
|
default:
|
|
throw new IllegalStateException();
|
|
}
|
|
}
|
|
|
|
public void postTick() {
|
|
// if we did this in pretick, it would suck
|
|
// we use the time between ticks as calculation time
|
|
// therefore, we only cancel and recalculate after the tick for the current path has executed
|
|
// "it would suck" means it would actually execute a path every other tick
|
|
if (command == null) {
|
|
return;
|
|
}
|
|
PathingBehavior p = baritone.getPathingBehavior();
|
|
switch (command.commandType) {
|
|
case FORCE_REVALIDATE_GOAL_AND_PATH:
|
|
if (command.goal == null || forceRevalidate(command.goal) || revalidateGoal(command.goal)) {
|
|
// pwnage
|
|
p.softCancelIfSafe();
|
|
}
|
|
p.secretInternalSetGoalAndPath(command.goal);
|
|
break;
|
|
case REVALIDATE_GOAL_AND_PATH:
|
|
if (Baritone.settings().cancelOnGoalInvalidation.get() && (command.goal == null || revalidateGoal(command.goal))) {
|
|
p.softCancelIfSafe();
|
|
}
|
|
p.secretInternalSetGoalAndPath(command.goal);
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
|
|
public boolean forceRevalidate(Goal newGoal) {
|
|
PathExecutor current = baritone.getPathingBehavior().getCurrent();
|
|
if (current != null) {
|
|
if (newGoal.isInGoal(current.getPath().getDest())) {
|
|
return false;
|
|
}
|
|
return !newGoal.toString().equals(current.getPath().getGoal().toString());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean revalidateGoal(Goal newGoal) {
|
|
PathExecutor current = baritone.getPathingBehavior().getCurrent();
|
|
if (current != null) {
|
|
Goal intended = current.getPath().getGoal();
|
|
BlockPos end = current.getPath().getDest();
|
|
if (intended.isInGoal(end) && !newGoal.isInGoal(end)) {
|
|
// this path used to end in the goal
|
|
// but the goal has changed, so there's no reason to continue...
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
public PathingCommand executeProcesses() {
|
|
Stream<IBaritoneProcess> inContention = processes.stream()
|
|
.filter(IBaritoneProcess::isActive)
|
|
.sorted(Comparator.comparingDouble(IBaritoneProcess::priority).reversed());
|
|
|
|
|
|
Iterator<IBaritoneProcess> iterator = inContention.iterator();
|
|
while (iterator.hasNext()) {
|
|
IBaritoneProcess proc = iterator.next();
|
|
|
|
PathingCommand exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel());
|
|
if (exec == null) {
|
|
if (proc.isActive()) {
|
|
throw new IllegalStateException(proc.displayName() + " returned null PathingCommand");
|
|
}
|
|
proc.onLostControl();
|
|
} else {
|
|
inControlThisTick = proc;
|
|
if (!proc.isTemporary()) {
|
|
iterator.forEachRemaining(IBaritoneProcess::onLostControl);
|
|
}
|
|
return exec;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|