Merge branch 'elytra'
This commit is contained in:
@@ -23,6 +23,7 @@ import baritone.api.Settings;
|
||||
import baritone.api.behavior.IBehavior;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
@@ -40,6 +41,8 @@ import net.minecraft.client.Minecraft;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -76,6 +79,7 @@ public class Baritone implements IBaritone {
|
||||
private final ExploreProcess exploreProcess;
|
||||
private final FarmProcess farmProcess;
|
||||
private final InventoryPauserProcess inventoryPauserProcess;
|
||||
private final ElytraProcess elytraProcess;
|
||||
|
||||
private final PathingControlManager pathingControlManager;
|
||||
private final SelectionManager selectionManager;
|
||||
@@ -118,6 +122,7 @@ public class Baritone implements IBaritone {
|
||||
this.exploreProcess = this.registerProcess(ExploreProcess::new);
|
||||
this.farmProcess = this.registerProcess(FarmProcess::new);
|
||||
this.inventoryPauserProcess = this.registerProcess(InventoryPauserProcess::new);
|
||||
this.elytraProcess = this.registerProcess(ElytraProcess::create);
|
||||
this.registerProcess(BackfillProcess::new);
|
||||
}
|
||||
|
||||
@@ -230,6 +235,11 @@ public class Baritone implements IBaritone {
|
||||
return this.commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IElytraProcess getElytraProcess() {
|
||||
return this.elytraProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openClick() {
|
||||
new Thread(() -> {
|
||||
|
||||
@@ -28,6 +28,8 @@ import baritone.api.utils.Rotation;
|
||||
import baritone.behavior.look.ForkableRandom;
|
||||
import net.minecraft.network.play.client.CPacketPlayer;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
@@ -51,14 +53,19 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
|
||||
private final AimProcessor processor;
|
||||
|
||||
private final Deque<Float> smoothYawBuffer;
|
||||
private final Deque<Float> smoothPitchBuffer;
|
||||
|
||||
public LookBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
this.processor = new AimProcessor(baritone.getPlayerContext());
|
||||
this.smoothYawBuffer = new ArrayDeque<>();
|
||||
this.smoothPitchBuffer = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTarget(Rotation rotation, boolean blockInteract) {
|
||||
this.target = new Target(rotation, blockInteract);
|
||||
this.target = new Target(rotation, Target.Mode.resolve(ctx, blockInteract));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,10 +91,8 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
// Just return for PRE, we still want to set target to null on POST
|
||||
return;
|
||||
}
|
||||
if (this.target.mode == Target.Mode.SERVER) {
|
||||
this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch);
|
||||
}
|
||||
|
||||
this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch);
|
||||
final Rotation actual = this.processor.peekRotation(this.target.rotation);
|
||||
ctx.player().rotationYaw = actual.getYaw();
|
||||
ctx.player().rotationPitch = actual.getPitch();
|
||||
@@ -96,8 +101,24 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
case POST: {
|
||||
// Reset the player's rotations back to their original values
|
||||
if (this.prevRotation != null) {
|
||||
ctx.player().rotationYaw = this.prevRotation.getYaw();
|
||||
ctx.player().rotationPitch = this.prevRotation.getPitch();
|
||||
this.smoothYawBuffer.addLast(this.target.rotation.getYaw());
|
||||
while (this.smoothYawBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothYawBuffer.removeFirst();
|
||||
}
|
||||
this.smoothPitchBuffer.addLast(this.target.rotation.getPitch());
|
||||
while (this.smoothPitchBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothPitchBuffer.removeFirst();
|
||||
}
|
||||
if (this.target.mode == Target.Mode.SERVER) {
|
||||
ctx.player().rotationYaw = this.prevRotation.getYaw();
|
||||
ctx.player().rotationPitch = this.prevRotation.getPitch();
|
||||
} else if (ctx.player().isElytraFlying() ? Baritone.settings().elytraSmoothLook.value : Baritone.settings().smoothLook.value) {
|
||||
ctx.player().rotationYaw = (float) this.smoothYawBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getYaw());
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
ctx.player().rotationPitch = (float) this.smoothPitchBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getPitch());
|
||||
}
|
||||
}
|
||||
|
||||
this.prevRotation = null;
|
||||
}
|
||||
// The target is done being used for this game tick, so it can be invalidated
|
||||
@@ -279,9 +300,9 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
public final Rotation rotation;
|
||||
public final Mode mode;
|
||||
|
||||
public Target(Rotation rotation, boolean blockInteract) {
|
||||
public Target(Rotation rotation, Mode mode) {
|
||||
this.rotation = rotation;
|
||||
this.mode = Mode.resolve(blockInteract);
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
@@ -300,22 +321,26 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
*/
|
||||
NONE;
|
||||
|
||||
static Mode resolve(boolean blockInteract) {
|
||||
static Mode resolve(IPlayerContext ctx, boolean blockInteract) {
|
||||
final Settings settings = Baritone.settings();
|
||||
final boolean antiCheat = settings.antiCheatCompatibility.value;
|
||||
final boolean blockFreeLook = settings.blockFreeLook.value;
|
||||
final boolean freeLook = settings.freeLook.value;
|
||||
|
||||
if (!freeLook) return CLIENT;
|
||||
if (!blockFreeLook && blockInteract) return CLIENT;
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
// always need to set angles while flying
|
||||
return settings.elytraFreeLook.value ? SERVER : CLIENT;
|
||||
} else if (settings.freeLook.value) {
|
||||
// Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
|
||||
// rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
|
||||
// whatever the player is mousing over visually. Let's just settle for setting it silently.
|
||||
if (blockInteract) {
|
||||
return blockFreeLook ? SERVER : CLIENT;
|
||||
}
|
||||
return antiCheat ? SERVER : NONE;
|
||||
}
|
||||
|
||||
// Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
|
||||
// rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
|
||||
// whatever the player is mousing over visually. Let's just settle for setting it silently.
|
||||
if (antiCheat || blockInteract) return SERVER;
|
||||
|
||||
// Pathing regularly without antiCheatCompatibility, don't set the player rotation
|
||||
return NONE;
|
||||
// all freeLook settings are disabled so set the angles
|
||||
return CLIENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.process.ElytraProcess;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
@@ -309,7 +310,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
}
|
||||
|
||||
public boolean isSafeToCancel() {
|
||||
return current == null || safeToCancel;
|
||||
if (current == null) {
|
||||
return !baritone.getElytraProcess().isActive() || baritone.getElytraProcess().isSafeToCancel();
|
||||
}
|
||||
return safeToCancel;
|
||||
}
|
||||
|
||||
public void requestPause() {
|
||||
@@ -352,7 +356,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
}
|
||||
|
||||
// just cancel the current path
|
||||
private void secretInternalSegmentCancel() {
|
||||
public void secretInternalSegmentCancel() {
|
||||
queuePathEvent(PathEvent.CANCELED);
|
||||
synchronized (pathPlanLock) {
|
||||
getInProgress().ifPresent(AbstractNodeCostSearch::cancel);
|
||||
|
||||
@@ -66,7 +66,8 @@ public final class DefaultCommands {
|
||||
new WaypointsCommand(baritone),
|
||||
new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"),
|
||||
new CommandAlias(baritone, "home", "Path to your home waypoint", "waypoints goto home"),
|
||||
new SelCommand(baritone)
|
||||
new SelCommand(baritone),
|
||||
new ElytraCommand(baritone)
|
||||
));
|
||||
ExecutionControlCommands prc = new ExecutionControlCommands(baritone);
|
||||
commands.add(prc.pauseCommand);
|
||||
|
||||
232
src/main/java/baritone/command/defaults/ElytraCommand.java
Normal file
232
src/main/java/baritone/command/defaults/ElytraCommand.java
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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.command.defaults;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.exception.CommandInvalidStateException;
|
||||
import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.process.ICustomGoalProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraft.util.text.event.ClickEvent;
|
||||
import net.minecraft.util.text.event.HoverEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
|
||||
|
||||
public class ElytraCommand extends Command {
|
||||
|
||||
public ElytraCommand(IBaritone baritone) {
|
||||
super(baritone, "elytra");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
final ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess();
|
||||
final IElytraProcess elytra = baritone.getElytraProcess();
|
||||
if (args.hasExactlyOne() && args.peekString().equals("supported")) {
|
||||
logDirect(elytra.isLoaded() ? "yes" : unsupportedSystemMessage());
|
||||
return;
|
||||
}
|
||||
if (!elytra.isLoaded()) {
|
||||
throw new CommandInvalidStateException(unsupportedSystemMessage());
|
||||
}
|
||||
|
||||
if (!args.hasAny()) {
|
||||
if (Baritone.settings().elytraTermsAccepted.value) {
|
||||
if (detectOn2b2t()) {
|
||||
warn2b2t();
|
||||
}
|
||||
} else {
|
||||
gatekeep();
|
||||
}
|
||||
Goal iGoal = customGoalProcess.mostRecentGoal();
|
||||
if (iGoal == null) {
|
||||
throw new CommandInvalidStateException("No goal has been set");
|
||||
}
|
||||
if (ctx.player().dimension != -1) {
|
||||
throw new CommandInvalidStateException("Only works in the nether");
|
||||
}
|
||||
try {
|
||||
elytra.pathTo(iGoal);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new CommandInvalidStateException(ex.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final String action = args.getString();
|
||||
switch (action) {
|
||||
case "reset": {
|
||||
elytra.resetState();
|
||||
logDirect("Reset state but still flying to same goal");
|
||||
break;
|
||||
}
|
||||
case "repack": {
|
||||
elytra.repackChunks();
|
||||
logDirect("Queued all loaded chunks for repacking");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new CommandInvalidStateException("Invalid action");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void warn2b2t() {
|
||||
if (!Baritone.settings().elytraPredictTerrain.value) {
|
||||
if (ctx.playerFeet().distanceSq(0, 0, 0) > 2000 * 2000) {
|
||||
TextComponentString clippy = new TextComponentString("");
|
||||
clippy.appendText("It looks like you're on 2b2t and more than 2000 blocks from spawn. It is recommended that you ");
|
||||
TextComponentString predictTerrain = new TextComponentString("enable elytraPredictTerrain");
|
||||
predictTerrain.getStyle().setUnderlined(true).setBold(true).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraPredictTerrain true"))).setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraPredictTerrain true"));
|
||||
clippy.appendSibling(predictTerrain);
|
||||
logDirect(clippy);
|
||||
}
|
||||
} else {
|
||||
long seed = Baritone.settings().elytraNetherSeed.value;
|
||||
if (seed != NEW_2B2T_SEED && seed != OLD_2B2T_SEED) {
|
||||
logDirect(new TextComponentString("It looks like you're on 2b2t, but elytraNetherSeed is incorrect.")); // match color
|
||||
logDirect(suggest2b2tSeeds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ITextComponent suggest2b2tSeeds() {
|
||||
TextComponentString clippy = new TextComponentString("");
|
||||
clippy.appendText("Within a few hundred blocks of spawn/axis/highways/etc, the terrain is too fragmented to be predictable. Baritone Elytra will still work, just with backtracking. ");
|
||||
clippy.appendText("However, once you get more than a few thousand blocks out, you should try ");
|
||||
TextComponentString olderSeed = new TextComponentString("the older seed (click here)");
|
||||
olderSeed.getStyle().setUnderlined(true).setBold(true).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraNetherSeed " + OLD_2B2T_SEED))).setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + OLD_2B2T_SEED));
|
||||
clippy.appendSibling(olderSeed);
|
||||
clippy.appendText(". Once you're further out into newer terrain generation (this includes everything 1.12 and upwards), you should try ");
|
||||
TextComponentString newerSeed = new TextComponentString("the newer seed (click here)");
|
||||
newerSeed.getStyle().setUnderlined(true).setBold(true).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraNetherSeed " + NEW_2B2T_SEED))).setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + NEW_2B2T_SEED));
|
||||
clippy.appendSibling(newerSeed);
|
||||
clippy.appendText(". ");
|
||||
return clippy;
|
||||
}
|
||||
|
||||
private void gatekeep() {
|
||||
TextComponentString gatekeep = new TextComponentString("");
|
||||
gatekeep.appendText("To disable this message, enable the setting elytraTermsAccepted\n");
|
||||
gatekeep.appendText("Baritone Elytra is an experimental feature. It is only intended for long distance travel in the Nether using fireworks for vanilla boost. It will not work with any other mods (\"hacks\") for non-vanilla boost. ");
|
||||
TextComponentString gatekeep2 = new TextComponentString("If you want Baritone to attempt to take off from the ground for you, you can enable the elytraAutoJump setting (not advisable on laggy servers!). ");
|
||||
gatekeep2.getStyle().setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraAutoJump true")));
|
||||
gatekeep.appendSibling(gatekeep2);
|
||||
TextComponentString gatekeep3 = new TextComponentString("If you want Baritone to go slower, enable the elytraConserveFireworks setting and/or decrease the elytraFireworkSpeed setting. ");
|
||||
gatekeep3.getStyle().setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraConserveFireworks true\n" + Baritone.settings().prefix.value + "set elytraFireworkSpeed 0.6\n(the 0.6 number is just an example, tweak to your liking)")));
|
||||
gatekeep.appendSibling(gatekeep3);
|
||||
TextComponentString gatekeep4 = new TextComponentString("Baritone Elytra ");
|
||||
TextComponentString red = new TextComponentString("wants to know the seed");
|
||||
red.getStyle().setColor(TextFormatting.RED).setUnderlined(true).setBold(true);
|
||||
gatekeep4.appendSibling(red);
|
||||
gatekeep4.appendText(" of the world you are in. If it doesn't have the correct seed, it will frequently backtrack. It uses the seed to generate terrain far beyond what you can see, since terrain obstacles in the Nether can be much larger than your render distance. ");
|
||||
gatekeep.appendSibling(gatekeep4);
|
||||
gatekeep.appendText("\n");
|
||||
if (detectOn2b2t()) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("It looks like you're on 2b2t, so elytraPredictTerrain is defaulting to true. ");
|
||||
gatekeep5.appendSibling(suggest2b2tSeeds());
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
gatekeep5.appendText("You are using the newer seed. ");
|
||||
} else if (Baritone.settings().elytraNetherSeed.value == OLD_2B2T_SEED) {
|
||||
gatekeep5.appendText("You are using the older seed. ");
|
||||
} else {
|
||||
gatekeep5.appendText("Defaulting to the newer seed. ");
|
||||
Baritone.settings().elytraNetherSeed.value = NEW_2B2T_SEED;
|
||||
}
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
} else {
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone doesn't know the seed of your world. Set it with: " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere\n");
|
||||
gatekeep5.appendText("For the time being, elytraPredictTerrain is defaulting to false since the seed is unknown.");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
Baritone.settings().elytraPredictTerrain.value = false;
|
||||
} else {
|
||||
if (Baritone.settings().elytraPredictTerrain.value) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone Elytra is predicting terrain assuming that " + Baritone.settings().elytraNetherSeed.value + " is the correct seed. Change that with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, or disable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain false");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
} else {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone Elytra is not predicting terrain. If you don't know the seed, this is the correct thing to do. If you do know the seed, input it with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, and then enable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain true");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
}
|
||||
}
|
||||
}
|
||||
logDirect(gatekeep);
|
||||
}
|
||||
|
||||
private boolean detectOn2b2t() {
|
||||
ServerData data = ctx.minecraft().getCurrentServerData();
|
||||
return data != null && data.serverIP.toLowerCase().contains("2b2t");
|
||||
}
|
||||
|
||||
private static final long OLD_2B2T_SEED = -4100785268875389365L;
|
||||
private static final long NEW_2B2T_SEED = 146008555100680L;
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
TabCompleteHelper helper = new TabCompleteHelper();
|
||||
if (args.hasExactlyOne()) {
|
||||
helper.append("reset", "repack", "supported");
|
||||
}
|
||||
return helper.filterPrefix(args.getString()).stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortDesc() {
|
||||
return "elytra time";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLongDesc() {
|
||||
return Arrays.asList(
|
||||
"The elytra command tells baritone to, in the nether, automatically fly to the current goal.",
|
||||
"",
|
||||
"Usage:",
|
||||
"> elytra - fly to the current goal",
|
||||
"> elytra reset - Resets the state of the process, but will try to keep flying to the same goal.",
|
||||
"> elytra repack - Queues all of the chunks in render distance to be given to the native library.",
|
||||
"> elytra supported - Tells you if baritone ships a native library that is compatible with your PC."
|
||||
);
|
||||
}
|
||||
|
||||
private static String unsupportedSystemMessage() {
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osName = System.getProperty("os.name");
|
||||
return String.format(
|
||||
"Legacy architectures are not supported. Your CPU is %s and your operating system is %s. " +
|
||||
"Supported architectures are 64 bit x86, and 64 bit ARM. Supported operating systems are Windows, " +
|
||||
"Linux, and Mac",
|
||||
osArch, osName
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,12 @@ import baritone.api.event.events.type.EventState;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.event.listener.IGameEventListener;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.Pair;
|
||||
import baritone.cache.CachedChunk;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
@@ -59,6 +63,11 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
listeners.forEach(l -> l.onTick(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTick(TickEvent event) {
|
||||
listeners.forEach(l -> l.onPostTick(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPlayerUpdate(PlayerUpdateEvent event) {
|
||||
listeners.forEach(l -> l.onPlayerUpdate(event));
|
||||
@@ -75,13 +84,10 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onChunkEvent(ChunkEvent event) {
|
||||
public void onChunkEvent(ChunkEvent event) {
|
||||
EventState state = event.getState();
|
||||
ChunkEvent.Type type = event.getType();
|
||||
|
||||
boolean isPostPopulate = state == EventState.POST
|
||||
&& (type == ChunkEvent.Type.POPULATE_FULL || type == ChunkEvent.Type.POPULATE_PARTIAL);
|
||||
|
||||
World world = baritone.getPlayerContext().world();
|
||||
|
||||
// Whenever the server sends us to another dimension, chunks are unloaded
|
||||
@@ -91,7 +97,7 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
&& type == ChunkEvent.Type.UNLOAD
|
||||
&& world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ());
|
||||
|
||||
if (isPostPopulate || isPreUnload) {
|
||||
if (event.isPostPopulate() || isPreUnload) {
|
||||
baritone.getWorldProvider().ifWorldLoaded(worldData -> {
|
||||
Chunk chunk = world.getChunk(event.getX(), event.getZ());
|
||||
worldData.getCachedWorld().queueForPacking(chunk);
|
||||
@@ -102,6 +108,25 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
listeners.forEach(l -> l.onChunkEvent(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockChange(BlockChangeEvent event) {
|
||||
if (Baritone.settings().repackOnAnyBlockChange.value) {
|
||||
final boolean keepingTrackOf = event.getBlocks().stream()
|
||||
.map(Pair::second).map(IBlockState::getBlock)
|
||||
.anyMatch(CachedChunk.BLOCKS_TO_KEEP_TRACK_OF::contains);
|
||||
|
||||
if (keepingTrackOf) {
|
||||
baritone.getWorldProvider().ifWorldLoaded(worldData -> {
|
||||
final World world = baritone.getPlayerContext().world();
|
||||
ChunkPos pos = event.getChunkPos();
|
||||
worldData.getCachedWorld().queueForPacking(world.getChunk(pos.x, pos.z));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
listeners.forEach(l -> l.onBlockChange(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onRenderPass(RenderEvent event) {
|
||||
listeners.forEach(l -> l.onRenderPass(event));
|
||||
|
||||
@@ -66,11 +66,13 @@ public class CalculationContext {
|
||||
public final boolean allowJumpAt256;
|
||||
public final boolean allowParkourAscend;
|
||||
public final boolean assumeWalkOnWater;
|
||||
public boolean allowFallIntoLava;
|
||||
public final int frostWalker;
|
||||
public final boolean allowDiagonalDescend;
|
||||
public final boolean allowDiagonalAscend;
|
||||
public final boolean allowDownward;
|
||||
public final int maxFallHeightNoWater;
|
||||
public int minFallHeight;
|
||||
public int maxFallHeightNoWater;
|
||||
public final int maxFallHeightBucket;
|
||||
public final double waterWalkSpeed;
|
||||
public final double breakBlockAdditionalCost;
|
||||
@@ -105,10 +107,12 @@ public class CalculationContext {
|
||||
this.allowJumpAt256 = Baritone.settings().allowJumpAt256.value;
|
||||
this.allowParkourAscend = Baritone.settings().allowParkourAscend.value;
|
||||
this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.value;
|
||||
this.allowFallIntoLava = false; // Super secret internal setting for ElytraBehavior
|
||||
this.frostWalker = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.FROST_WALKER, baritone.getPlayerContext().player());
|
||||
this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.value;
|
||||
this.allowDiagonalAscend = Baritone.settings().allowDiagonalAscend.value;
|
||||
this.allowDownward = Baritone.settings().allowDownward.value;
|
||||
this.minFallHeight = 3; // Minimum fall height used by MovementFall
|
||||
this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.value;
|
||||
this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.value;
|
||||
int depth = EnchantmentHelper.getDepthStriderModifier(player);
|
||||
|
||||
@@ -154,10 +154,11 @@ public class MovementDescend extends Movement {
|
||||
// this check prevents it from getting the block at y=-1 and crashing
|
||||
return false;
|
||||
}
|
||||
boolean reachedMinimum = fallHeight >= context.minFallHeight;
|
||||
IBlockState ontoBlock = context.get(destX, newY, destZ);
|
||||
int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY
|
||||
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar;
|
||||
if (MovementHelper.isWater(ontoBlock.getBlock())) {
|
||||
if (reachedMinimum && MovementHelper.isWater(ontoBlock.getBlock())) {
|
||||
if (!MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) {
|
||||
return false;
|
||||
}
|
||||
@@ -178,6 +179,14 @@ public class MovementDescend extends Movement {
|
||||
res.cost = tentativeCost;// TODO incorporate water swim up cost?
|
||||
return false;
|
||||
}
|
||||
if (reachedMinimum && context.allowFallIntoLava && MovementHelper.isLava(ontoBlock.getBlock())) {
|
||||
// found a fall into lava
|
||||
res.x = destX;
|
||||
res.y = newY;
|
||||
res.z = destZ;
|
||||
res.cost = tentativeCost;
|
||||
return false;
|
||||
}
|
||||
if (unprotectedFallHeight <= 11 && (ontoBlock.getBlock() == Blocks.VINE || ontoBlock.getBlock() == Blocks.LADDER)) {
|
||||
// if fall height is greater than or equal to 11, we don't actually grab on to vines or ladders. the more you know
|
||||
// this effectively "resets" our falling speed
|
||||
@@ -195,7 +204,7 @@ public class MovementDescend extends Movement {
|
||||
if (MovementHelper.isBottomSlab(ontoBlock)) {
|
||||
return false; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
|
||||
}
|
||||
if (unprotectedFallHeight <= context.maxFallHeightNoWater + 1) {
|
||||
if (reachedMinimum && unprotectedFallHeight <= context.maxFallHeightNoWater + 1) {
|
||||
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
|
||||
res.x = destX;
|
||||
res.y = newY + 1;
|
||||
@@ -203,7 +212,7 @@ public class MovementDescend extends Movement {
|
||||
res.cost = tentativeCost;
|
||||
return false;
|
||||
}
|
||||
if (context.hasWaterBucket && unprotectedFallHeight <= context.maxFallHeightBucket + 1) {
|
||||
if (reachedMinimum && context.hasWaterBucket && unprotectedFallHeight <= context.maxFallHeightBucket + 1) {
|
||||
res.x = destX;
|
||||
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
|
||||
res.z = destZ;
|
||||
|
||||
@@ -36,6 +36,11 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC
|
||||
*/
|
||||
private Goal goal;
|
||||
|
||||
/**
|
||||
* The most recent goal. Not invalidated upon {@link #onLostControl()}
|
||||
*/
|
||||
private Goal mostRecentGoal;
|
||||
|
||||
/**
|
||||
* The current process state.
|
||||
*
|
||||
@@ -50,6 +55,10 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC
|
||||
@Override
|
||||
public void setGoal(Goal goal) {
|
||||
this.goal = goal;
|
||||
this.mostRecentGoal = goal;
|
||||
if (baritone.getElytraProcess().isActive()) {
|
||||
baritone.getElytraProcess().pathTo(goal);
|
||||
}
|
||||
if (this.state == State.NONE) {
|
||||
this.state = State.GOAL_SET;
|
||||
}
|
||||
@@ -68,6 +77,11 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC
|
||||
return this.goal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Goal mostRecentGoal() {
|
||||
return this.mostRecentGoal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return this.state != State.NONE;
|
||||
|
||||
566
src/main/java/baritone/process/ElytraProcess.java
Normal file
566
src/main/java/baritone/process/ElytraProcess.java
Normal file
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* 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.process;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.event.events.*;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalBlock;
|
||||
import baritone.api.pathing.goals.GoalXZ;
|
||||
import baritone.api.pathing.goals.GoalYLevel;
|
||||
import baritone.api.pathing.movement.IMovement;
|
||||
import baritone.api.pathing.path.IPathExecutor;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.movements.MovementFall;
|
||||
import baritone.process.elytra.ElytraBehavior;
|
||||
import baritone.process.elytra.NetherPathfinderContext;
|
||||
import baritone.process.elytra.NullElytraProcess;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
|
||||
public class ElytraProcess extends BaritoneProcessHelper implements IBaritoneProcess, IElytraProcess, AbstractGameEventListener {
|
||||
public State state;
|
||||
private boolean goingToLandingSpot;
|
||||
private BetterBlockPos landingSpot;
|
||||
private boolean reachedGoal; // this basically just prevents potential notification spam
|
||||
private Goal goal;
|
||||
private ElytraBehavior behavior;
|
||||
private boolean predictingTerrain;
|
||||
|
||||
private ElytraProcess(Baritone baritone) {
|
||||
super(baritone);
|
||||
baritone.getGameEventHandler().registerEventListener(this);
|
||||
}
|
||||
|
||||
public static <T extends IElytraProcess> T create(final Baritone baritone) {
|
||||
return (T) (NetherPathfinderContext.isSupported()
|
||||
? new ElytraProcess(baritone)
|
||||
: new NullElytraProcess(baritone));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return this.behavior != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
BlockPos destination = this.currentDestination();
|
||||
this.onLostControl();
|
||||
if (destination != null) {
|
||||
this.pathTo(destination);
|
||||
this.repackChunks();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String AUTO_JUMP_FAILURE_MSG = "Failed to compute a walking path to a spot to jump off from. Consider starting from a higher location, near an overhang. Or, you can disable elytraAutoJump and just manually begin gliding.";
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
final long seedSetting = Baritone.settings().elytraNetherSeed.value;
|
||||
if (seedSetting != this.behavior.context.getSeed()) {
|
||||
logDirect("Nether seed changed, recalculating path");
|
||||
this.resetState();
|
||||
}
|
||||
if (predictingTerrain != Baritone.settings().elytraPredictTerrain.value) {
|
||||
logDirect("elytraPredictTerrain setting changed, recalculating path");
|
||||
predictingTerrain = Baritone.settings().elytraPredictTerrain.value;
|
||||
this.resetState();
|
||||
}
|
||||
|
||||
this.behavior.onTick();
|
||||
|
||||
if (calcFailed) {
|
||||
onLostControl();
|
||||
logDirect(AUTO_JUMP_FAILURE_MSG);
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
boolean safetyLanding = false;
|
||||
if (ctx.player().isElytraFlying() && shouldLandForSafety()) {
|
||||
if (Baritone.settings().elytraAllowEmergencyLand.value) {
|
||||
logDirect("Emergency landing - almost out of elytra durability or fireworks");
|
||||
safetyLanding = true;
|
||||
} else {
|
||||
logDirect("almost out of elytra durability or fireworks, but I'm going to continue since elytraAllowEmergencyLand is false");
|
||||
}
|
||||
}
|
||||
if (ctx.player().isElytraFlying() && this.state != State.LANDING && (this.behavior.pathManager.isComplete() || safetyLanding)) {
|
||||
final BetterBlockPos last = this.behavior.pathManager.path.getLast();
|
||||
logDirect((last != null) + " " + this.state + " " + safetyLanding + " " + goingToLandingSpot);
|
||||
if (last != null && (ctx.player().getDistanceSqToCenter(last) < (48 * 48) || safetyLanding) && (!goingToLandingSpot || (safetyLanding && this.landingSpot == null))) {
|
||||
logDirect("Path complete, picking a nearby safe landing spot...");
|
||||
BetterBlockPos landingSpot = findSafeLandingSpot(ctx.playerFeet());
|
||||
// if this fails we will just keep orbiting the last node until we run out of rockets or the user intervenes
|
||||
if (landingSpot != null) {
|
||||
this.pathTo0(landingSpot, true);
|
||||
this.landingSpot = landingSpot;
|
||||
}
|
||||
this.goingToLandingSpot = true;
|
||||
}
|
||||
|
||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < 1) {
|
||||
if (Baritone.settings().notificationOnPathComplete.value && !reachedGoal) {
|
||||
logNotification("Pathing complete", false);
|
||||
}
|
||||
if (Baritone.settings().disconnectOnArrival.value && !reachedGoal) {
|
||||
// don't be active when the user logs back in
|
||||
this.onLostControl();
|
||||
ctx.world().sendQuittingDisconnectingPacket();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
reachedGoal = true;
|
||||
|
||||
// we are goingToLandingSpot and we are in the last node of the path
|
||||
if (this.goingToLandingSpot) {
|
||||
this.state = State.LANDING;
|
||||
logDirect("Above the landing spot, landing...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.LANDING) {
|
||||
final BetterBlockPos endPos = this.landingSpot != null ? this.landingSpot : behavior.pathManager.path.getLast();
|
||||
if (ctx.player().isElytraFlying() && endPos != null) {
|
||||
Vec3d from = ctx.player().getPositionVector();
|
||||
Vec3d to = new Vec3d(((double) endPos.x) + 0.5, from.y, ((double) endPos.z) + 0.5);
|
||||
Rotation rotation = RotationUtils.calcRotationFromVec3d(from, to, ctx.playerRotations());
|
||||
baritone.getLookBehavior().updateTarget(new Rotation(rotation.getYaw(), 0), false); // this will be overwritten, probably, by behavior tick
|
||||
|
||||
if (ctx.player().posY < endPos.y - LANDING_COLUMN_HEIGHT) {
|
||||
logDirect("bad landing spot, trying again...");
|
||||
landingSpotIsBad(endPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
behavior.landingMode = this.state == State.LANDING;
|
||||
this.goal = null;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
behavior.tick();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
} else if (this.state == State.LANDING) {
|
||||
if (Math.sqrt(ctx.player().motionX * ctx.player().motionX + ctx.player().motionZ * ctx.player().motionZ) > 0.001) {
|
||||
logDirect("Landed, but still moving, waiting for velocity to die down... ");
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true);
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
logDirect("Done :)");
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
this.onLostControl();
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
if (this.state == State.FLYING || this.state == State.START_FLYING) {
|
||||
this.state = ctx.player().onGround && Baritone.settings().elytraAutoJump.value
|
||||
? State.LOCATE_JUMP
|
||||
: State.START_FLYING;
|
||||
}
|
||||
|
||||
if (this.state == State.LOCATE_JUMP) {
|
||||
if (shouldLandForSafety()) {
|
||||
logDirect("Not taking off, because elytra durability or fireworks are so low that I would immediately emergency land anyway.");
|
||||
onLostControl();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
if (this.goal == null) {
|
||||
this.goal = new GoalYLevel(31);
|
||||
}
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
if (executor != null && executor.getPath().getGoal() == this.goal) {
|
||||
final IMovement fall = executor.getPath().movements().stream()
|
||||
.filter(movement -> movement instanceof MovementFall)
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (fall != null) {
|
||||
final BetterBlockPos from = new BetterBlockPos(
|
||||
(fall.getSrc().x + fall.getDest().x) / 2,
|
||||
(fall.getSrc().y + fall.getDest().y) / 2,
|
||||
(fall.getSrc().z + fall.getDest().z) / 2
|
||||
);
|
||||
behavior.pathManager.pathToDestination(from).whenComplete((result, ex) -> {
|
||||
if (ex == null) {
|
||||
this.state = State.GET_TO_JUMP;
|
||||
return;
|
||||
}
|
||||
onLostControl();
|
||||
});
|
||||
this.state = State.PAUSE;
|
||||
} else {
|
||||
onLostControl();
|
||||
logDirect(AUTO_JUMP_FAILURE_MSG);
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
}
|
||||
return new PathingCommandContext(this.goal, PathingCommandType.SET_GOAL_AND_PAUSE, new WalkOffCalculationContext(baritone));
|
||||
}
|
||||
|
||||
// yucky
|
||||
if (this.state == State.PAUSE) {
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
if (this.state == State.GET_TO_JUMP) {
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
final boolean canStartFlying = ctx.player().fallDistance > 1.0f
|
||||
&& !isSafeToCancel
|
||||
&& executor != null
|
||||
&& executor.getPath().movements().get(executor.getPosition()) instanceof MovementFall;
|
||||
|
||||
if (canStartFlying) {
|
||||
this.state = State.START_FLYING;
|
||||
} else {
|
||||
return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.START_FLYING) {
|
||||
if (!isSafeToCancel) {
|
||||
// owned
|
||||
baritone.getPathingBehavior().secretInternalSegmentCancel();
|
||||
}
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
if (ctx.player().fallDistance > 1.0f) {
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, true);
|
||||
}
|
||||
}
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
public void landingSpotIsBad(BetterBlockPos endPos) {
|
||||
badLandingSpots.add(endPos);
|
||||
goingToLandingSpot = false;
|
||||
this.landingSpot = null;
|
||||
this.state = State.FLYING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
this.goal = null;
|
||||
this.goingToLandingSpot = false;
|
||||
this.landingSpot = null;
|
||||
this.reachedGoal = false;
|
||||
this.state = State.START_FLYING; // TODO: null state?
|
||||
destroyBehaviorAsync();
|
||||
}
|
||||
|
||||
private void destroyBehaviorAsync() {
|
||||
ElytraBehavior behavior = this.behavior;
|
||||
if (behavior != null) {
|
||||
this.behavior = null;
|
||||
Baritone.getExecutor().execute(behavior::destroy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double priority() {
|
||||
return 0; // higher priority than CustomGoalProcess
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
return "Elytra - " + this.state.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repackChunks() {
|
||||
if (this.behavior != null) {
|
||||
this.behavior.repackChunks();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos currentDestination() {
|
||||
return this.behavior != null ? this.behavior.destination : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
this.pathTo0(destination, false);
|
||||
}
|
||||
|
||||
private void pathTo0(BlockPos destination, boolean appendDestination) {
|
||||
if (ctx.player() == null || ctx.player().dimension != -1) {
|
||||
return;
|
||||
}
|
||||
this.onLostControl();
|
||||
this.predictingTerrain = Baritone.settings().elytraPredictTerrain.value;
|
||||
this.behavior = new ElytraBehavior(this.baritone, this, destination, appendDestination);
|
||||
if (ctx.world() != null) {
|
||||
this.behavior.repackChunks();
|
||||
}
|
||||
this.behavior.pathTo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(Goal iGoal) {
|
||||
final int x;
|
||||
final int y;
|
||||
final int z;
|
||||
if (iGoal instanceof GoalXZ) {
|
||||
GoalXZ goal = (GoalXZ) iGoal;
|
||||
x = goal.getX();
|
||||
y = 64;
|
||||
z = goal.getZ();
|
||||
} else if (iGoal instanceof GoalBlock) {
|
||||
GoalBlock goal = (GoalBlock) iGoal;
|
||||
x = goal.x;
|
||||
y = goal.y;
|
||||
z = goal.z;
|
||||
} else {
|
||||
throw new IllegalArgumentException("The goal must be a GoalXZ or GoalBlock");
|
||||
}
|
||||
if (y <= 0 || y >= 128) {
|
||||
throw new IllegalArgumentException("The y of the goal is not between 0 and 128");
|
||||
}
|
||||
this.pathTo(new BlockPos(x, y, z));
|
||||
}
|
||||
|
||||
private boolean shouldLandForSafety() {
|
||||
ItemStack chest = ctx.player().inventory.armorInventory.get(2);
|
||||
if (chest.getItem() != Items.ELYTRA || chest.getItem().getMaxDamage() - chest.getItemDamage() < Baritone.settings().elytraMinimumDurability.value) {
|
||||
// elytrabehavior replaces when durability <= minimumDurability, so if durability < minimumDurability then we can reasonably assume that the elytra will soon be broken without replacement
|
||||
return true;
|
||||
}
|
||||
NonNullList<ItemStack> inv = ctx.player().inventory.mainInventory;
|
||||
int qty = 0;
|
||||
for (int i = 0; i < 36; i++) {
|
||||
if (ElytraBehavior.isFireworks(inv.get(i))) {
|
||||
qty += inv.get(i).getCount();
|
||||
}
|
||||
}
|
||||
if (qty <= Baritone.settings().elytraMinFireworksBeforeLanding.value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeToCancel() {
|
||||
return !this.isActive() || !(this.state == State.FLYING || this.state == State.START_FLYING);
|
||||
}
|
||||
|
||||
public enum State {
|
||||
LOCATE_JUMP("Finding spot to jump off"),
|
||||
PAUSE("Waiting for elytra path"),
|
||||
GET_TO_JUMP("Walking to takeoff"),
|
||||
START_FLYING("Begin flying"),
|
||||
FLYING("Flying"),
|
||||
LANDING("Landing");
|
||||
|
||||
public final String description;
|
||||
|
||||
State(String desc) {
|
||||
this.description = desc;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRenderPass(RenderEvent event) {
|
||||
if (this.behavior != null) this.behavior.onRenderPass(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWorldEvent(WorldEvent event) {
|
||||
if (event.getWorld() != null && event.getState() == EventState.POST) {
|
||||
// Exiting the world, just destroy
|
||||
destroyBehaviorAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkEvent(ChunkEvent event) {
|
||||
if (this.behavior != null) this.behavior.onChunkEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockChange(BlockChangeEvent event) {
|
||||
if (this.behavior != null) this.behavior.onBlockChange(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivePacket(PacketEvent event) {
|
||||
if (this.behavior != null) this.behavior.onReceivePacket(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTick(TickEvent event) {
|
||||
IBaritoneProcess procThisTick = baritone.getPathingControlManager().mostRecentInControl().orElse(null);
|
||||
if (this.behavior != null && procThisTick == this) this.behavior.onPostTick(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom calculation context which makes the player fall into lava
|
||||
*/
|
||||
public static final class WalkOffCalculationContext extends CalculationContext {
|
||||
|
||||
public WalkOffCalculationContext(IBaritone baritone) {
|
||||
super(baritone, true);
|
||||
this.allowFallIntoLava = true;
|
||||
this.minFallHeight = 8;
|
||||
this.maxFallHeightNoWater = 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double costOfPlacingAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double breakCostMultiplierAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double placeBucketCost() {
|
||||
return COST_INF;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInBounds(BlockPos pos) {
|
||||
return pos.getY() >= 0 && pos.getY() < 128;
|
||||
}
|
||||
|
||||
private boolean isSafeBlock(Block block) {
|
||||
return block == Blocks.NETHERRACK || block == Blocks.GRAVEL || (block == Blocks.NETHER_BRICK && Baritone.settings().elytraAllowLandOnNetherFortress.value);
|
||||
}
|
||||
|
||||
private boolean isSafeBlock(BlockPos pos) {
|
||||
return isSafeBlock(ctx.world().getBlockState(pos).getBlock());
|
||||
}
|
||||
|
||||
private boolean isAtEdge(BlockPos pos) {
|
||||
return !isSafeBlock(pos.north())
|
||||
|| !isSafeBlock(pos.south())
|
||||
|| !isSafeBlock(pos.east())
|
||||
|| !isSafeBlock(pos.west())
|
||||
// corners
|
||||
|| !isSafeBlock(pos.north().west())
|
||||
|| !isSafeBlock(pos.north().east())
|
||||
|| !isSafeBlock(pos.south().west())
|
||||
|| !isSafeBlock(pos.south().east());
|
||||
}
|
||||
|
||||
private boolean isColumnAir(BlockPos landingSpot, int minHeight) {
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos(landingSpot);
|
||||
final int maxY = mut.getY() + minHeight;
|
||||
for (int y = mut.getY() + 1; y <= maxY; y++) {
|
||||
mut.setPos(mut.getX(), y, mut.getZ());
|
||||
if (!ctx.world().isAirBlock(mut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasAirBubble(BlockPos pos) {
|
||||
final int radius = 4; // Half of the full width, rounded down, as we're counting blocks in each direction from the center
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos();
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
mut.setPos(pos.getX() + x, pos.getY() + y, pos.getZ() + z);
|
||||
if (!ctx.world().isAirBlock(mut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private BetterBlockPos checkLandingSpot(BlockPos pos, LongOpenHashSet checkedSpots) {
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos(pos);
|
||||
while (mut.getY() >= 0) {
|
||||
if (checkedSpots.contains(mut.toLong())) {
|
||||
return null;
|
||||
}
|
||||
checkedSpots.add(mut.toLong());
|
||||
Block block = ctx.world().getBlockState(mut).getBlock();
|
||||
|
||||
if (isSafeBlock(block)) {
|
||||
if (!isAtEdge(mut)) {
|
||||
return new BetterBlockPos(mut);
|
||||
}
|
||||
return null;
|
||||
} else if (block != Blocks.AIR) {
|
||||
return null;
|
||||
}
|
||||
mut.setPos(mut.getX(), mut.getY() - 1, mut.getZ());
|
||||
}
|
||||
return null; // void
|
||||
}
|
||||
|
||||
private static final int LANDING_COLUMN_HEIGHT = 15;
|
||||
private Set<BetterBlockPos> badLandingSpots = new HashSet<>();
|
||||
|
||||
private BetterBlockPos findSafeLandingSpot(BetterBlockPos start) {
|
||||
Queue<BetterBlockPos> queue = new PriorityQueue<>(Comparator.<BetterBlockPos>comparingInt(pos -> (pos.x - start.x) * (pos.x - start.x) + (pos.z - start.z) * (pos.z - start.z)).thenComparingInt(pos -> -pos.y));
|
||||
Set<BetterBlockPos> visited = new HashSet<>();
|
||||
LongOpenHashSet checkedPositions = new LongOpenHashSet();
|
||||
queue.add(start);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
BetterBlockPos pos = queue.poll();
|
||||
if (ctx.world().isBlockLoaded(pos, false) && isInBounds(pos) && ctx.world().getBlockState(pos).getBlock() == Blocks.AIR) {
|
||||
BetterBlockPos actualLandingSpot = checkLandingSpot(pos, checkedPositions);
|
||||
if (actualLandingSpot != null && isColumnAir(actualLandingSpot, LANDING_COLUMN_HEIGHT) && hasAirBubble(actualLandingSpot.up(LANDING_COLUMN_HEIGHT)) && !badLandingSpots.contains(actualLandingSpot.up(LANDING_COLUMN_HEIGHT))) {
|
||||
return actualLandingSpot.up(LANDING_COLUMN_HEIGHT);
|
||||
}
|
||||
if (visited.add(pos.north())) queue.add(pos.north());
|
||||
if (visited.add(pos.east())) queue.add(pos.east());
|
||||
if (visited.add(pos.south())) queue.add(pos.south());
|
||||
if (visited.add(pos.west())) queue.add(pos.west());
|
||||
if (visited.add(pos.up())) queue.add(pos.up());
|
||||
if (visited.add(pos.down())) queue.add(pos.down());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
import dev.babbaj.pathfinder.NetherPathfinder;
|
||||
import dev.babbaj.pathfinder.Octree;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class BlockStateOctreeInterface {
|
||||
|
||||
private final NetherPathfinderContext context;
|
||||
private final long contextPtr;
|
||||
transient long chunkPtr;
|
||||
|
||||
// Guarantee that the first lookup will fetch the context by setting MAX_VALUE
|
||||
private int prevChunkX = Integer.MAX_VALUE;
|
||||
private int prevChunkZ = Integer.MAX_VALUE;
|
||||
|
||||
public BlockStateOctreeInterface(final NetherPathfinderContext context) {
|
||||
this.context = context;
|
||||
this.contextPtr = context.context;
|
||||
}
|
||||
|
||||
public boolean get0(final int x, final int y, final int z) {
|
||||
if ((y | (127 - y)) < 0) {
|
||||
return false;
|
||||
}
|
||||
final int chunkX = x >> 4;
|
||||
final int chunkZ = z >> 4;
|
||||
if (this.chunkPtr == 0 | ((chunkX ^ this.prevChunkX) | (chunkZ ^ this.prevChunkZ)) != 0) {
|
||||
this.prevChunkX = chunkX;
|
||||
this.prevChunkZ = chunkZ;
|
||||
this.chunkPtr = NetherPathfinder.getOrCreateChunk(this.contextPtr, chunkX, chunkZ);
|
||||
}
|
||||
return Octree.getBlock(this.chunkPtr, x & 0xF, y & 0x7F, z & 0xF);
|
||||
}
|
||||
}
|
||||
1359
src/main/java/baritone/process/elytra/ElytraBehavior.java
Normal file
1359
src/main/java/baritone/process/elytra/ElytraBehavior.java
Normal file
File diff suppressed because it is too large
Load Diff
65
src/main/java/baritone/process/elytra/NetherPath.java
Normal file
65
src/main/java/baritone/process/elytra/NetherPath.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class NetherPath extends AbstractList<BetterBlockPos> {
|
||||
|
||||
private static final NetherPath EMPTY_PATH = new NetherPath(Collections.emptyList());
|
||||
|
||||
private final List<BetterBlockPos> backing;
|
||||
|
||||
NetherPath(List<BetterBlockPos> backing) {
|
||||
this.backing = backing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BetterBlockPos get(int index) {
|
||||
return this.backing.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.backing.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The last position in the path, or {@code null} if empty
|
||||
*/
|
||||
public BetterBlockPos getLast() {
|
||||
return this.isEmpty() ? null : this.backing.get(this.backing.size() - 1);
|
||||
}
|
||||
|
||||
public Vec3d getVec(int index) {
|
||||
final BetterBlockPos pos = this.get(index);
|
||||
return new Vec3d(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
public static NetherPath emptyPath() {
|
||||
return EMPTY_PATH;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.BlockChangeEvent;
|
||||
import baritone.utils.accessor.IBitArray;
|
||||
import baritone.utils.accessor.IBlockStateContainer;
|
||||
import dev.babbaj.pathfinder.NetherPathfinder;
|
||||
import dev.babbaj.pathfinder.Octree;
|
||||
import dev.babbaj.pathfinder.PathSegment;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.BitArray;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.chunk.BlockStateContainer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class NetherPathfinderContext {
|
||||
|
||||
private static final IBlockState AIR_BLOCK_STATE = Blocks.AIR.getDefaultState();
|
||||
// This lock must be held while there are active pointers to chunks in java,
|
||||
// but we just hold it for the entire tick so we don't have to think much about it.
|
||||
public final Object cullingLock = new Object();
|
||||
|
||||
// Visible for access in BlockStateOctreeInterface
|
||||
final long context;
|
||||
private final long seed;
|
||||
private final ExecutorService executor;
|
||||
|
||||
public NetherPathfinderContext(long seed) {
|
||||
this.context = NetherPathfinder.newContext(seed);
|
||||
this.seed = seed;
|
||||
this.executor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
public void queueCacheCulling(int chunkX, int chunkZ, int maxDistanceBlocks, BlockStateOctreeInterface boi) {
|
||||
this.executor.execute(() -> {
|
||||
synchronized (this.cullingLock) {
|
||||
boi.chunkPtr = 0L;
|
||||
NetherPathfinder.cullFarChunks(this.context, chunkX, chunkZ, maxDistanceBlocks);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void queueForPacking(final Chunk chunkIn) {
|
||||
final SoftReference<Chunk> ref = new SoftReference<>(chunkIn);
|
||||
this.executor.execute(() -> {
|
||||
// TODO: Prioritize packing recent chunks and/or ones that the path goes through,
|
||||
// and prune the oldest chunks per chunkPackerQueueMaxSize
|
||||
final Chunk chunk = ref.get();
|
||||
if (chunk != null) {
|
||||
long ptr = NetherPathfinder.getOrCreateChunk(this.context, chunk.x, chunk.z);
|
||||
writeChunkData(chunk, ptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void queueBlockUpdate(BlockChangeEvent event) {
|
||||
this.executor.execute(() -> {
|
||||
ChunkPos chunkPos = event.getChunkPos();
|
||||
long ptr = NetherPathfinder.getChunkPointer(this.context, chunkPos.x, chunkPos.z);
|
||||
if (ptr == 0) return; // this shouldn't ever happen
|
||||
event.getBlocks().forEach(pair -> {
|
||||
BlockPos pos = pair.first();
|
||||
if (pos.getY() >= 128) return;
|
||||
boolean isSolid = pair.second() != AIR_BLOCK_STATE;
|
||||
Octree.setBlock(ptr, pos.getX() & 15, pos.getY(), pos.getZ() & 15, isSolid);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<PathSegment> pathFindAsync(final BlockPos src, final BlockPos dst) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
final PathSegment segment = NetherPathfinder.pathFind(
|
||||
this.context,
|
||||
src.getX(), src.getY(), src.getZ(),
|
||||
dst.getX(), dst.getY(), dst.getZ(),
|
||||
true,
|
||||
false,
|
||||
10000,
|
||||
!Baritone.settings().elytraPredictTerrain.value
|
||||
);
|
||||
if (segment == null) {
|
||||
throw new PathCalculationException("Path calculation failed");
|
||||
}
|
||||
return segment;
|
||||
}, this.executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a raytrace from the given start position to the given end position, returning {@code true} if there is
|
||||
* visibility between the two points.
|
||||
*
|
||||
* @param startX The start X coordinate
|
||||
* @param startY The start Y coordinate
|
||||
* @param startZ The start Z coordinate
|
||||
* @param endX The end X coordinate
|
||||
* @param endY The end Y coordinate
|
||||
* @param endZ The end Z coordinate
|
||||
* @return {@code true} if there is visibility between the points
|
||||
*/
|
||||
public boolean raytrace(final double startX, final double startY, final double startZ,
|
||||
final double endX, final double endY, final double endZ) {
|
||||
return NetherPathfinder.isVisible(this.context, true, startX, startY, startZ, endX, endY, endZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a raytrace from the given start position to the given end position, returning {@code true} if there is
|
||||
* visibility between the two points.
|
||||
*
|
||||
* @param start The starting point
|
||||
* @param end The ending point
|
||||
* @return {@code true} if there is visibility between the points
|
||||
*/
|
||||
public boolean raytrace(final Vec3d start, final Vec3d end) {
|
||||
return NetherPathfinder.isVisible(this.context, true, start.x, start.y, start.z, end.x, end.y, end.z);
|
||||
}
|
||||
|
||||
public boolean raytrace(final int count, final double[] src, final double[] dst, final int visibility) {
|
||||
switch (visibility) {
|
||||
case Visibility.ALL:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, false) == -1;
|
||||
case Visibility.NONE:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, true) == -1;
|
||||
case Visibility.ANY:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, true) != -1;
|
||||
default:
|
||||
throw new IllegalArgumentException("lol");
|
||||
}
|
||||
}
|
||||
|
||||
public void raytrace(final int count, final double[] src, final double[] dst, final boolean[] hitsOut, final double[] hitPosOut) {
|
||||
NetherPathfinder.raytrace(this.context, true, count, src, dst, hitsOut, hitPosOut);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
NetherPathfinder.cancel(this.context);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
this.cancel();
|
||||
// Ignore anything that was queued up, just shutdown the executor
|
||||
this.executor.shutdownNow();
|
||||
|
||||
try {
|
||||
while (!this.executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)) {}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
NetherPathfinder.freeContext(this.context);
|
||||
}
|
||||
|
||||
public long getSeed() {
|
||||
return this.seed;
|
||||
}
|
||||
|
||||
private static void writeChunkData(Chunk chunk, long ptr) {
|
||||
try {
|
||||
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
|
||||
for (int y0 = 0; y0 < 8; y0++) {
|
||||
final ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
|
||||
if (extendedblockstorage == null) {
|
||||
continue;
|
||||
}
|
||||
final BlockStateContainer bsc = extendedblockstorage.getData();
|
||||
final int airId = ((IBlockStateContainer) bsc).getPalette().idFor(AIR_BLOCK_STATE);
|
||||
// pasted from FasterWorldScanner
|
||||
final BitArray array = ((IBlockStateContainer) bsc).getStorage();
|
||||
if (array == null) continue;
|
||||
final long[] longArray = array.getBackingLongArray();
|
||||
final int arraySize = array.size();
|
||||
final int bitsPerEntry = ((IBitArray) array).getBitsPerEntry();
|
||||
final long maxEntryValue = ((IBitArray) array).getMaxEntryValue();
|
||||
|
||||
final int yReal = y0 << 4;
|
||||
for (int idx = 0, kl = bitsPerEntry - 1; idx < arraySize; idx++, kl += bitsPerEntry) {
|
||||
final int i = idx * bitsPerEntry;
|
||||
final int j = i >> 6;
|
||||
final int l = i & 63;
|
||||
final int k = kl >> 6;
|
||||
final long jl = longArray[j] >>> l;
|
||||
|
||||
final int id;
|
||||
if (j == k) {
|
||||
id = (int) (jl & maxEntryValue);
|
||||
} else {
|
||||
id = (int) ((jl | longArray[k] << (64 - l)) & maxEntryValue);
|
||||
}
|
||||
int x = (idx & 15);
|
||||
int y = yReal + (idx >> 8);
|
||||
int z = ((idx >> 4) & 15);
|
||||
Octree.setBlock(ptr, x, y, z, id != airId);
|
||||
}
|
||||
}
|
||||
Octree.setIsFromJava(ptr);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Visibility {
|
||||
|
||||
public static final int ALL = 0;
|
||||
public static final int NONE = 1;
|
||||
public static final int ANY = 2;
|
||||
|
||||
private Visibility() {}
|
||||
}
|
||||
|
||||
public static boolean isSupported() {
|
||||
return NetherPathfinder.isThisSystemSupported();
|
||||
}
|
||||
}
|
||||
92
src/main/java/baritone/process/elytra/NullElytraProcess.java
Normal file
92
src/main/java/baritone/process/elytra/NullElytraProcess.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class NullElytraProcess extends BaritoneProcessHelper implements IElytraProcess {
|
||||
|
||||
public NullElytraProcess(Baritone baritone) {
|
||||
super(baritone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repackChunks() {
|
||||
throw new UnsupportedOperationException("Called repackChunks() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos currentDestination() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
throw new UnsupportedOperationException("Called pathTo() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(Goal destination) {
|
||||
throw new UnsupportedOperationException("Called pathTo() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
throw new UnsupportedOperationException("Called onTick on NullElytraProcess");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
return "NullElytraProcess";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeToCancel() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class PathCalculationException extends RuntimeException {
|
||||
|
||||
public PathCalculationException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
83
src/main/java/baritone/process/elytra/UnpackedSegment.java
Normal file
83
src/main/java/baritone/process/elytra/UnpackedSegment.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.process.elytra;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import dev.babbaj.pathfinder.PathSegment;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class UnpackedSegment {
|
||||
|
||||
private final Stream<BetterBlockPos> path;
|
||||
private final boolean finished;
|
||||
|
||||
public UnpackedSegment(Stream<BetterBlockPos> path, boolean finished) {
|
||||
this.path = path;
|
||||
this.finished = finished;
|
||||
}
|
||||
|
||||
public UnpackedSegment append(Stream<BetterBlockPos> other, boolean otherFinished) {
|
||||
// The new segment is only finished if the one getting added on is
|
||||
return new UnpackedSegment(Stream.concat(this.path, other), otherFinished);
|
||||
}
|
||||
|
||||
public UnpackedSegment prepend(Stream<BetterBlockPos> other) {
|
||||
return new UnpackedSegment(Stream.concat(other, this.path), this.finished);
|
||||
}
|
||||
|
||||
public List<BetterBlockPos> collect() {
|
||||
final List<BetterBlockPos> path = this.path.collect(Collectors.toList());
|
||||
|
||||
// Remove backtracks
|
||||
final Map<BetterBlockPos, Integer> positionFirstSeen = new HashMap<>();
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
BetterBlockPos pos = path.get(i);
|
||||
if (positionFirstSeen.containsKey(pos)) {
|
||||
int j = positionFirstSeen.get(pos);
|
||||
while (i > j) {
|
||||
path.remove(i);
|
||||
i--;
|
||||
}
|
||||
} else {
|
||||
positionFirstSeen.put(pos, i);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return this.finished;
|
||||
}
|
||||
|
||||
public static UnpackedSegment from(final PathSegment segment) {
|
||||
return new UnpackedSegment(
|
||||
Arrays.stream(segment.packed).mapToObj(BetterBlockPos::deserializeFromLong),
|
||||
segment.finished
|
||||
);
|
||||
}
|
||||
}
|
||||
37
src/main/java/baritone/utils/BaritoneMath.java
Normal file
37
src/main/java/baritone/utils/BaritoneMath.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class BaritoneMath {
|
||||
|
||||
private static final double FLOOR_DOUBLE_D = 1_073_741_824.0;
|
||||
private static final int FLOOR_DOUBLE_I = 1_073_741_824;
|
||||
|
||||
private BaritoneMath() {}
|
||||
|
||||
public static int fastFloor(final double v) {
|
||||
return (int) (v + FLOOR_DOUBLE_D) - FLOOR_DOUBLE_I;
|
||||
}
|
||||
|
||||
public static int fastCeil(final double v) {
|
||||
return FLOOR_DOUBLE_I - (int) (FLOOR_DOUBLE_D - v);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -122,4 +123,16 @@ public interface IRenderer {
|
||||
emitAABB(aabb);
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
static void emitLine(Vec3d start, Vec3d end) {
|
||||
emitLine(start.x, start.y, start.z, end.x, end.y, end.z);
|
||||
}
|
||||
|
||||
static void emitLine(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
double vpX = renderManager.viewerPosX;
|
||||
double vpY = renderManager.viewerPosY;
|
||||
double vpZ = renderManager.viewerPosZ;
|
||||
buffer.pos(x1 - vpX, y1 - vpY, z1 - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 - vpX, y2 - vpY, z2 - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri
|
||||
}
|
||||
|
||||
private boolean inControl() {
|
||||
for (Input input : new Input[]{Input.MOVE_FORWARD, Input.MOVE_BACK, Input.MOVE_LEFT, Input.MOVE_RIGHT, Input.SNEAK}) {
|
||||
for (Input input : new Input[]{Input.MOVE_FORWARD, Input.MOVE_BACK, Input.MOVE_LEFT, Input.MOVE_RIGHT, Input.SNEAK, Input.JUMP}) {
|
||||
if (isInputForcedDown(input)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package baritone.utils;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.event.events.RenderEvent;
|
||||
import baritone.api.pathing.calc.IPath;
|
||||
import baritone.api.pathing.goals.*;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
@@ -90,33 +89,36 @@ public final class PathRenderer implements IRenderer {
|
||||
// Render the current path, if there is one
|
||||
if (current != null && current.getPath() != null) {
|
||||
int renderBegin = Math.max(current.getPosition() - 3, 0);
|
||||
drawPath(current.getPath(), renderBegin, settings.colorCurrentPath.value, settings.fadePath.value, 10, 20);
|
||||
drawPath(current.getPath().positions(), renderBegin, settings.colorCurrentPath.value, settings.fadePath.value, 10, 20);
|
||||
}
|
||||
|
||||
if (next != null && next.getPath() != null) {
|
||||
drawPath(next.getPath(), 0, settings.colorNextPath.value, settings.fadePath.value, 10, 20);
|
||||
drawPath(next.getPath().positions(), 0, settings.colorNextPath.value, settings.fadePath.value, 10, 20);
|
||||
}
|
||||
|
||||
// If there is a path calculation currently running, render the path calculation process
|
||||
behavior.getInProgress().ifPresent(currentlyRunning -> {
|
||||
currentlyRunning.bestPathSoFar().ifPresent(p -> {
|
||||
drawPath(p, 0, settings.colorBestPathSoFar.value, settings.fadePath.value, 10, 20);
|
||||
drawPath(p.positions(), 0, settings.colorBestPathSoFar.value, settings.fadePath.value, 10, 20);
|
||||
});
|
||||
|
||||
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
|
||||
drawPath(mr, 0, settings.colorMostRecentConsidered.value, settings.fadePath.value, 10, 20);
|
||||
drawPath(mr.positions(), 0, settings.colorMostRecentConsidered.value, settings.fadePath.value, 10, 20);
|
||||
drawManySelectionBoxes(ctx.player(), Collections.singletonList(mr.getDest()), settings.colorMostRecentConsidered.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void drawPath(IPath path, int startIndex, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) {
|
||||
public static void drawPath(List<BetterBlockPos> positions, int startIndex, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) {
|
||||
drawPath(positions, startIndex, color, fadeOut, fadeStart0, fadeEnd0, 0.5D);
|
||||
}
|
||||
|
||||
public static void drawPath(List<BetterBlockPos> positions, int startIndex, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0, double offset) {
|
||||
IRenderer.startLines(color, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value);
|
||||
|
||||
int fadeStart = fadeStart0 + startIndex;
|
||||
int fadeEnd = fadeEnd0 + startIndex;
|
||||
|
||||
List<BetterBlockPos> positions = path.positions();
|
||||
for (int i = startIndex, next; i < positions.size() - 1; i = next) {
|
||||
BetterBlockPos start = positions.get(i);
|
||||
BetterBlockPos end = positions.get(next = i + 1);
|
||||
@@ -147,30 +149,31 @@ public final class PathRenderer implements IRenderer {
|
||||
IRenderer.glColor(color, alpha);
|
||||
}
|
||||
|
||||
emitLine(start.x, start.y, start.z, end.x, end.y, end.z);
|
||||
emitPathLine(start.x, start.y, start.z, end.x, end.y, end.z, offset);
|
||||
}
|
||||
|
||||
IRenderer.endLines(settings.renderPathIgnoreDepth.value);
|
||||
}
|
||||
|
||||
private static void emitLine(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
private static void emitPathLine(double x1, double y1, double z1, double x2, double y2, double z2, double offset) {
|
||||
final double extraOffset = offset + 0.03D;
|
||||
double vpX = renderManager.viewerPosX;
|
||||
double vpY = renderManager.viewerPosY;
|
||||
double vpZ = renderManager.viewerPosZ;
|
||||
boolean renderPathAsFrickinThingy = !settings.renderPathAsLine.value;
|
||||
|
||||
buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + 0.5D - vpX, y2 + 0.5D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + offset - vpX, y1 + offset - vpY, z1 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + offset - vpX, y2 + offset - vpY, z2 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
|
||||
if (renderPathAsFrickinThingy) {
|
||||
buffer.pos(x2 + 0.5D - vpX, y2 + 0.5D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + 0.5D - vpX, y2 + 0.53D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + offset - vpX, y2 + offset - vpY, z2 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + offset - vpX, y2 + extraOffset - vpY, z2 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
|
||||
buffer.pos(x2 + 0.5D - vpX, y2 + 0.53D - vpY, z2 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + 0.5D - vpX, y1 + 0.53D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x2 + offset - vpX, y2 + extraOffset - vpY, z2 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + offset - vpX, y1 + extraOffset - vpY, z1 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
|
||||
buffer.pos(x1 + 0.5D - vpX, y1 + 0.53D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + 0.5D - vpX, y1 + 0.5D - vpY, z1 + 0.5D - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + offset - vpX, y1 + extraOffset - vpY, z1 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
buffer.pos(x1 + offset - vpX, y1 + offset - vpY, z1 + offset - vpZ).color(color[0], color[1], color[2], color[3]).endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +199,7 @@ public final class PathRenderer implements IRenderer {
|
||||
IRenderer.endLines(settings.renderSelectionBoxesIgnoreDepth.value);
|
||||
}
|
||||
|
||||
private static void drawGoal(Entity player, Goal goal, float partialTicks, Color color) {
|
||||
public static void drawGoal(Entity player, Goal goal, float partialTicks, Color color) {
|
||||
drawGoal(player, goal, partialTicks, color, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.process.CustomGoalProcess;
|
||||
import baritone.process.ElytraProcess;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.*;
|
||||
@@ -99,6 +101,8 @@ public class PathingControlManager implements IPathingControlManager {
|
||||
// get rid of the in progress stuff from the last process
|
||||
}
|
||||
switch (command.commandType) {
|
||||
case SET_GOAL_AND_PAUSE:
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
case REQUEST_PAUSE:
|
||||
p.requestPause();
|
||||
break;
|
||||
@@ -107,10 +111,6 @@ public class PathingControlManager implements IPathingControlManager {
|
||||
p.cancelSegmentIfSafe();
|
||||
break;
|
||||
case FORCE_REVALIDATE_GOAL_AND_PATH:
|
||||
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
}
|
||||
break;
|
||||
case REVALIDATE_GOAL_AND_PATH:
|
||||
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
@@ -119,7 +119,7 @@ public class PathingControlManager implements IPathingControlManager {
|
||||
case SET_GOAL_AND_PATH:
|
||||
// now this i can do
|
||||
if (command.goal != null) {
|
||||
baritone.getPathingBehavior().secretInternalSetGoalAndPath(command);
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.accessor;
|
||||
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
|
||||
public interface IEntityFireworkRocket {
|
||||
|
||||
EntityLivingBase getBoostedEntity();
|
||||
}
|
||||
Reference in New Issue
Block a user