diff --git a/src/api/java/baritone/api/process/IBaritoneProcess.java b/src/api/java/baritone/api/process/IBaritoneProcess.java index 6405be94..9eef16fc 100644 --- a/src/api/java/baritone/api/process/IBaritoneProcess.java +++ b/src/api/java/baritone/api/process/IBaritoneProcess.java @@ -44,4 +44,6 @@ public interface IBaritoneProcess { double priority(); // tenor be like IBaritone associatedWith(); // which bot is this associated with (5000000iq forward thinking) + + String displayName(); } diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java index 24eaf3a8..d4f7af44 100644 --- a/src/api/java/baritone/api/process/PathingCommandType.java +++ b/src/api/java/baritone/api/process/PathingCommandType.java @@ -18,10 +18,12 @@ package baritone.api.process; public enum PathingCommandType { - SET_GOAL_AND_PATH, // if you do this one with a null goal it should continue - REQUEST_PAUSE, + SET_GOAL_AND_PATH, // self explanatory, if you do this one with a null goal it should continue - // if you do this one with a null goal it should cancel - REVALIDATE_GOAL_AND_PATH, // idkkkkkkk - FORCE_REVALIDATE_GOAL_AND_PATH // idkkkkkkkkkkkkkkkkkkkkkkkk + REQUEST_PAUSE, // this one just pauses. it doesn't change the goal. + + CANCEL_AND_SET_GOAL, // cancel the current path, and set the goal (regardless of if it's null) + + REVALIDATE_GOAL_AND_PATH, // set the goal, revalidate if cancelOnGoalInvalidation is true, then path. if the goal is null, it will cancel (but only if that setting is true) + FORCE_REVALIDATE_GOAL_AND_PATH // set the goal, revalidate current goal (cancel if no longer valid), cancel if the provided goal is null } diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index 055929f0..b655dddc 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -21,7 +21,6 @@ import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.event.listener.IGameEventListener; -import baritone.api.process.IBaritoneProcess; import baritone.behavior.Behavior; import baritone.behavior.LookBehavior; import baritone.behavior.MemoryBehavior; @@ -114,8 +113,8 @@ public enum Baritone implements IBaritone { followProcess = new FollowProcess(this); mineProcess = new MineProcess(this); new ExampleBaritoneControl(this); - new CustomGoalProcess(this); // very high iq - new GetToBlockProcess(this); + customGoalProcess = new CustomGoalProcess(this); // very high iq + getToBlockProcess = new GetToBlockProcess(this); } if (BaritoneAutoTest.ENABLE_AUTO_TEST) { registerEventListener(BaritoneAutoTest.INSTANCE); @@ -160,8 +159,12 @@ public enum Baritone implements IBaritone { this.registerEventListener(behavior); } - public void registerProcess(IBaritoneProcess process) { + public CustomGoalProcess getCustomGoalProcess() { + return customGoalProcess; + } + public GetToBlockProcess getGetToBlockProcess() { // very very high iq + return getToBlockProcess; } @Override diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 1cfd98bd..15dffae8 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -52,6 +52,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, private Goal goal; + private boolean safeToCancel; + private boolean pauseRequestedLastTick; + private volatile boolean isPathCalcInProgress; private final Object pathCalcLock = new Object(); @@ -81,7 +84,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, public void onTick(TickEvent event) { dispatchEvents(); if (event.getType() == TickEvent.Type.OUT) { - cancel(); + secretInternalSegmentCancel(); return; } tickPath(); @@ -89,10 +92,17 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } private void tickPath() { + baritone.getPathingControlManager().doTheThingWithTheStuff(); + if (pauseRequestedLastTick && safeToCancel) { + pauseRequestedLastTick = false; + baritone.getInputOverrideHandler().clearAllKeys(); + BlockBreakHelper.stopBreakingBlock(); + return; + } if (current == null) { return; } - boolean safe = current.onTick(); + safeToCancel = current.onTick(); synchronized (pathPlanLock) { if (current.failed() || current.finished()) { current = null; @@ -134,7 +144,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return; } // at this point, we know current is in progress - if (safe && next != null && next.snipsnapifpossible()) { + if (safeToCancel && next != null && next.snipsnapifpossible()) { // a movement just ended; jump directly onto the next path logDebug("Splicing into planned next path early..."); queuePathEvent(PathEvent.SPLICING_ONTO_NEXT_EARLY); @@ -191,13 +201,13 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition())); } - public void setGoal(Goal goal) { + public void secretInternalSetGoal(Goal goal) { this.goal = goal; } - public boolean setGoalAndPath(Goal goal) { - setGoal(goal); - return path(); + public boolean secretInternalSetGoalAndPath(Goal goal) { + secretInternalSetGoal(goal); + return secretInternalPath(); } @Override @@ -225,22 +235,40 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return this.current != null; } + public boolean isSafeToCancel() { + return current == null || safeToCancel; + } + + public void requestPause() { + pauseRequestedLastTick = true; + } + + public boolean cancelSegmentIfSafe() { + if (isSafeToCancel()) { + secretInternalSegmentCancel(); + return true; + } + return false; + } + @Override public void cancelEverything() { - + secretInternalSegmentCancel(); + baritone.getPathingControlManager().cancelEverything(); } // just cancel the current path - public void cancel() { + public void secretInternalSegmentCancel() { queuePathEvent(PathEvent.CANCELED); current = null; next = null; - Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); + baritone.getInputOverrideHandler().clearAllKeys(); AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel); BlockBreakHelper.stopBreakingBlock(); } public void forceCancel() { // NOT exposed on public api + cancelEverything(); isPathCalcInProgress = false; } @@ -249,7 +277,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, * * @return true if this call started path calculation, false if it was already calculating or executing a path */ - public boolean path() { + public boolean secretInternalPath() { if (goal == null) { return false; } diff --git a/src/main/java/baritone/process/CustomGoalProcess.java b/src/main/java/baritone/process/CustomGoalProcess.java index 08b142ff..e402edf8 100644 --- a/src/main/java/baritone/process/CustomGoalProcess.java +++ b/src/main/java/baritone/process/CustomGoalProcess.java @@ -22,8 +22,11 @@ import baritone.api.pathing.goals.Goal; import baritone.api.process.ICustomGoalProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; +import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.utils.BaritoneProcessHelper; +import java.util.Objects; + /** * As set by ExampleBaritoneControl or something idk * @@ -31,35 +34,72 @@ import baritone.utils.BaritoneProcessHelper; */ public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomGoalProcess { private Goal goal; - private boolean active; + private State state; + private int ticksExecuting; public CustomGoalProcess(Baritone baritone) { - super(baritone); + super(baritone, 3); } @Override public void setGoal(Goal goal) { this.goal = goal; + state = State.GOAL_SET; } @Override public void path() { - active = true; + if (goal == null) { + goal = baritone.getPathingBehavior().getGoal(); + } + state = State.PATH_REQUESTED; + } + + private enum State { + NONE, + GOAL_SET, + PATH_REQUESTED, + EXECUTING, + } @Override public boolean isActive() { - return active; + return state != State.NONE; } @Override public PathingCommand onTick() { - active = false; // only do this once - return new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PATH); + switch (state) { + case GOAL_SET: + if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal(), goal)) { + state = State.NONE; + } + return new PathingCommand(goal, PathingCommandType.CANCEL_AND_SET_GOAL); + case PATH_REQUESTED: + PathingCommand ret = new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PATH); + state = State.EXECUTING; + ticksExecuting = 0; + return ret; + case EXECUTING: + if (ticksExecuting++ > 2 && !baritone.getPathingBehavior().isPathing() && !AbstractNodeCostSearch.getCurrentlyRunning().isPresent()) { + onLostControl(); + } + return new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PATH); + default: + throw new IllegalStateException(); + } } @Override public void onLostControl() { - active = false; + state = State.NONE; + goal = null; + ticksExecuting = 0; + } + + @Override + public String displayName() { + return "Custom Goal " + goal; } } diff --git a/src/main/java/baritone/process/FollowProcess.java b/src/main/java/baritone/process/FollowProcess.java index dcfa21a0..bfccdda7 100644 --- a/src/main/java/baritone/process/FollowProcess.java +++ b/src/main/java/baritone/process/FollowProcess.java @@ -18,9 +18,9 @@ package baritone.process; import baritone.Baritone; -import baritone.api.process.IFollowProcess; import baritone.api.pathing.goals.GoalNear; import baritone.api.pathing.goals.GoalXZ; +import baritone.api.process.IFollowProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; import baritone.utils.BaritoneProcessHelper; @@ -37,7 +37,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo private Entity following; public FollowProcess(Baritone baritone) { - super(baritone); + super(baritone, 1); } @Override @@ -63,6 +63,11 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo following = null; } + @Override + public String displayName() { + return "Follow " + following; + } + @Override public void follow(Entity entity) { this.following = entity; diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 62dac26e..b2fd1363 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -38,7 +38,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl int tickCount = 0; public GetToBlockProcess(Baritone baritone) { - super(baritone); + super(baritone, 2); } @Override @@ -67,6 +67,9 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl Baritone.INSTANCE.getExecutor().execute(this::rescan); } Goal goal = new GoalComposite(knownLocations.stream().map(GoalGetToBlock::new).toArray(Goal[]::new)); + if (goal.isInGoal(playerFeet())) { + onLostControl(); + } return new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PATH); } @@ -76,6 +79,11 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl knownLocations = null; } + @Override + public String displayName() { + return "Get To Block " + gettingTo; + } + private void rescan() { knownLocations = MineProcess.searchWorld(Collections.singletonList(gettingTo), 64); } diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index a88fd537..823f2091 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -57,7 +57,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro private int tickCount; public MineProcess(Baritone baritone) { - super(baritone); + super(baritone, 0); } @Override @@ -79,7 +79,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain - Baritone.INSTANCE.getExecutor().execute(this::rescan); + baritone.getExecutor().execute(this::rescan); } if (Baritone.settings().legitMine.get()) { addNearby(); @@ -99,6 +99,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro mine(0, (Block[]) null); } + @Override + public String displayName() { + return "Mine " + mining; + } + private Goal updateGoal() { List locs = knownOreLocations; if (!locs.isEmpty()) { @@ -115,7 +120,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro // only in non-Xray mode (aka legit mode) do we do this if (branchPoint == null) { int y = Baritone.settings().legitMineYLevel.get(); - if (!associatedWith().getPathingBehavior().isPathing() && playerFeet().y == y) { + if (!baritone.getPathingBehavior().isPathing() && playerFeet().y == y) { // cool, path is over and we are at desired y branchPoint = playerFeet(); } else { diff --git a/src/main/java/baritone/utils/BaritoneAutoTest.java b/src/main/java/baritone/utils/BaritoneAutoTest.java index 70e1a70e..4aee4bd4 100644 --- a/src/main/java/baritone/utils/BaritoneAutoTest.java +++ b/src/main/java/baritone/utils/BaritoneAutoTest.java @@ -105,8 +105,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { } // Setup Baritone's pathing goal and (if needed) begin pathing - Baritone.INSTANCE.getPathingBehavior().setGoal(GOAL); - Baritone.INSTANCE.getPathingBehavior().path(); + Baritone.INSTANCE.getCustomGoalProcess().setGoalAndPath(GOAL); // If we have reached our goal, print a message and safely close the game if (GOAL.isInGoal(playerFeet())) { diff --git a/src/main/java/baritone/utils/BaritoneProcessHelper.java b/src/main/java/baritone/utils/BaritoneProcessHelper.java index 4ca0fe94..d01e815d 100644 --- a/src/main/java/baritone/utils/BaritoneProcessHelper.java +++ b/src/main/java/baritone/utils/BaritoneProcessHelper.java @@ -23,7 +23,7 @@ import baritone.api.process.IBaritoneProcess; public abstract class BaritoneProcessHelper implements IBaritoneProcess, Helper { public static final double DEFAULT_PRIORITY = 0; - private final Baritone baritone; + protected final Baritone baritone; private final double priority; public BaritoneProcessHelper(Baritone baritone) { diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index f461b9a7..90648245 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -33,6 +33,7 @@ import baritone.cache.WorldProvider; import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; +import baritone.process.CustomGoalProcess; import net.minecraft.block.Block; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.entity.Entity; @@ -99,6 +100,8 @@ public class ExampleBaritoneControl extends Behavior implements Helper { public boolean runCommand(String msg0) { String msg = msg0.toLowerCase(Locale.US).trim(); // don't reassign the argument LOL PathingBehavior pathingBehavior = baritone.getPathingBehavior(); + PathingControlManager pathControl = baritone.getPathingControlManager(); + CustomGoalProcess CGPgrey = baritone.getCustomGoalProcess(); List> toggleable = Baritone.settings().getAllValuesByType(Boolean.class); for (Settings.Setting setting : toggleable) { if (msg.equalsIgnoreCase(setting.getName())) { @@ -186,21 +189,19 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("unable to parse integer " + ex); return true; } - pathingBehavior.setGoal(goal); + CGPgrey.setGoal(goal); logDirect("Goal: " + goal); return true; } if (msg.equals("path")) { - if (!pathingBehavior.path()) { - if (pathingBehavior.getGoal() == null) { - logDirect("No goal."); - } else { - if (pathingBehavior.getGoal().isInGoal(playerFeet())) { - logDirect("Already in goal"); - } else { - logDirect("Currently executing a path. Please cancel it first."); - } - } + if (pathingBehavior.getGoal() == null) { + logDirect("No goal."); + } else if (pathingBehavior.getGoal().isInGoal(playerFeet())) { + logDirect("Already in goal"); + } else if (pathingBehavior.isPathing()) { + logDirect("Currently executing a path. Please cancel it first."); + } else { + CGPgrey.path(); } return true; } @@ -222,21 +223,20 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } if (msg.equals("axis")) { - pathingBehavior.setGoal(new GoalAxis()); - pathingBehavior.path(); + CGPgrey.setGoalAndPath(new GoalAxis()); return true; } if (msg.equals("cancel") || msg.equals("stop")) { baritone.getMineProcess().cancel(); baritone.getFollowProcess().cancel(); - pathingBehavior.cancel(); + pathingBehavior.cancelEverything(); logDirect("ok canceled"); return true; } if (msg.equals("forcecancel")) { baritone.getMineProcess().cancel(); baritone.getFollowProcess().cancel(); - pathingBehavior.cancel(); + pathingBehavior.cancelEverything(); AbstractNodeCostSearch.forceCancel(); pathingBehavior.forceCancel(); logDirect("ok force canceled"); @@ -259,15 +259,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Inverting goal of player feet"); runAwayFrom = playerFeet(); } - pathingBehavior.setGoal(new GoalRunAway(1, runAwayFrom) { + CGPgrey.setGoalAndPath(new GoalRunAway(1, runAwayFrom) { @Override public boolean isInGoal(int x, int y, int z) { return false; } }); - if (!pathingBehavior.path()) { - logDirect("Currently executing a path. Please cancel it first."); - } return true; } if (msg.startsWith("follow")) { @@ -337,7 +334,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { if (msg.startsWith("thisway")) { try { Goal goal = GoalXZ.fromDirection(playerFeetAsVec(), player().rotationYaw, Double.parseDouble(msg.substring(7).trim())); - pathingBehavior.setGoal(goal); + CGPgrey.setGoal(goal); logDirect("Goal: " + goal); } catch (NumberFormatException ex) { logDirect("Error unable to parse '" + msg.substring(7).trim() + "' to a double."); @@ -406,13 +403,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } } else { - List locs = baritone.getMineProcess().searchWorld(Collections.singletonList(block), 64); - if (locs.isEmpty()) { - logDirect("No locations for " + mining + " known, cancelling"); - return true; - } - pathingBehavior.setGoal(new GoalComposite(locs.stream().map(GoalGetToBlock::new).toArray(Goal[]::new))); - pathingBehavior.path(); + baritone.getGetToBlockProcess().getToBlock(block); return true; } } else { @@ -423,10 +414,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } } Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); - if (!pathingBehavior.path() && !goal.isInGoal(playerFeet())) { - logDirect("Currently executing a path. Please cancel it first."); - } + CGPgrey.setGoalAndPath(goal); return true; } if (msg.equals("spawn") || msg.equals("bed")) { @@ -436,10 +424,10 @@ public class ExampleBaritoneControl extends Behavior implements Helper { // for some reason the default spawnpoint is underground sometimes Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getZ()); logDirect("spawn not saved, defaulting to world spawn. set goal to " + goal); - pathingBehavior.setGoal(goal); + CGPgrey.setGoalAndPath(goal); } else { - Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); + Goal goal = new GoalGetToBlock(waypoint.getLocation()); + CGPgrey.setGoalAndPath(goal); logDirect("Set goal to most recent bed " + goal); } return true; @@ -455,8 +443,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("home not saved"); } else { Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); - pathingBehavior.path(); + CGPgrey.setGoalAndPath(goal); logDirect("Going to saved home " + goal); } return true; diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index 37c17614..55308daf 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -21,6 +21,7 @@ import baritone.Baritone; 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; @@ -39,43 +40,51 @@ public class PathingControlManager { } public void registerProcess(IBaritoneProcess process) { + process.onLostControl(); // make sure it's reset processes.add(process); } + public void cancelEverything() { + for (IBaritoneProcess proc : processes) { + proc.onLostControl(); + if (proc.isActive() && !proc.isTemporary()) { // it's okay for a temporary thing (like combat pause) to maintain control even if you say to cancel + // but not for a non temporary thing + throw new IllegalStateException(proc.displayName()); + } + } + } + public void doTheThingWithTheStuff() { PathingCommand cmd = doTheStuff(); if (cmd == null) { - baritone.getPathingBehavior().cancel(); return; } - + PathingBehavior p = baritone.getPathingBehavior(); switch (cmd.commandType) { case REQUEST_PAUSE: - // idk - // ask pathingbehavior if its safe + p.requestPause(); + break; + case CANCEL_AND_SET_GOAL: + p.secretInternalSetGoal(cmd.goal); + p.cancelSegmentIfSafe(); + break; case FORCE_REVALIDATE_GOAL_AND_PATH: - if (cmd.goal == null) { - baritone.getPathingBehavior().cancel(); // todo only if its safe - return; - } - // pwnage - baritone.getPathingBehavior().setGoal(cmd.goal); - if (revalidateGoal(cmd.goal)) { - baritone.getPathingBehavior().cancel(); // todo only if its safe + p.secretInternalSetGoalAndPath(cmd.goal); + if (cmd.goal == null || revalidateGoal(cmd.goal)) { + // pwnage + p.cancelSegmentIfSafe(); } + break; case REVALIDATE_GOAL_AND_PATH: - if (cmd.goal == null) { - baritone.getPathingBehavior().cancel(); // todo only if its safe - return; - } - baritone.getPathingBehavior().setGoal(cmd.goal); - if (Baritone.settings().cancelOnGoalInvalidation.get() && revalidateGoal(cmd.goal)) { - baritone.getPathingBehavior().cancel(); // todo only if its safe + p.secretInternalSetGoalAndPath(cmd.goal); + if (Baritone.settings().cancelOnGoalInvalidation.get() && (cmd.goal == null || revalidateGoal(cmd.goal))) { + p.cancelSegmentIfSafe(); } + break; case SET_GOAL_AND_PATH: // now this i can do if (cmd.goal != null) { - baritone.getPathingBehavior().setGoalAndPath(cmd.goal); + baritone.getPathingBehavior().secretInternalSetGoalAndPath(cmd.goal); } // breaks are for wusses!!!! } @@ -111,11 +120,12 @@ public class PathingControlManager { exec = proc.onTick(); if (exec == null) { if (proc.isActive()) { - throw new IllegalStateException(proc + ""); + throw new IllegalStateException(proc.displayName()); } proc.onLostControl(); continue; } + System.out.println("Executing command " + exec.commandType + " " + exec.goal + " from " + proc.displayName()); found = true; cancelOthers = !proc.isTemporary(); }