diff --git a/README.md b/README.md index 4c4b35a3..eb96e9e4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ [![Pull Requests](https://img.shields.io/github/issues-pr/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/pulls/) ![Code size](https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg) ![GitHub repo size](https://img.shields.io/github/repo-size/cabaletta/baritone.svg) +![](https://tokei.rs/b1/github/cabaletta/baritone?category=code) +![](https://tokei.rs/b1/github/cabaletta/baritone?category=files) [![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2) [![GitHub contributors](https://img.shields.io/github/contributors/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/graphs/contributors/) [![GitHub commits](https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg)](https://github.com/cabaletta/baritone/commit/) @@ -30,6 +32,8 @@ the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone Have committed at least once a day for the last 6 months =D 🦀 +1Leijurv3DWTrGAfmmiTphjhXLvQiHg7K2 + Here are some links to help to get started: - [Features](FEATURES.md) @@ -40,6 +44,8 @@ Here are some links to help to get started: - [Javadocs](https://baritone.leijurv.com/) +- [Settings](https://baritone.leijurv.com/baritone/api/Settings.html#allowBreak) + # Chat control - [Baritone chat control usage](USAGE.md) @@ -57,7 +63,7 @@ BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAnd ## Can I use Baritone as a library in my custom utility client? -Sure! (As long as usage is in compliance with the LGPL 3 License) +That's what it's for, sure! (As long as usage is in compliance with the LGPL 3 License) ## How is it so fast? diff --git a/USAGE.md b/USAGE.md index dab1edb1..391e5e45 100644 --- a/USAGE.md +++ b/USAGE.md @@ -43,7 +43,7 @@ Some common examples: For the rest of the commands, you can take a look at the code [here](https://github.com/cabaletta/baritone/blob/master/src/main/java/baritone/utils/ExampleBaritoneControl.java). -All the settings and documentation are here. If you find HTML easier to read than Javadoc, you can look here and navigate to Settings in the left sidebar. +All the settings and documentation are here. If you find HTML easier to read than Javadoc, you can look here. There are about a hundred settings, but here are some fun / interesting / important ones that you might want to look at changing in normal usage of Baritone. The documentation for each can be found at the above links. - `allowBreak` diff --git a/build.gradle b/build.gradle index ceb024c1..d31ea10e 100755 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ */ group 'baritone' -version '1.1.4' +version '1.1.5' buildscript { repositories { diff --git a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java index 4f7674f6..7e26dac1 100644 --- a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java +++ b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java @@ -17,8 +17,6 @@ package baritone.gradle.task; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; import org.gradle.api.DefaultTask; import java.io.File; @@ -26,7 +24,6 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; /** * @author Brady diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index ecadb571..4e1cc9cd 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -164,6 +164,11 @@ public final class Settings { */ public final Setting considerPotionEffects = new Setting<>(true); + /** + * Sprint and jump a block early on ascends wherever possible + */ + public final Setting sprintAscends = new Setting<>(true); + /** * This is the big A* setting. * As long as your cost heuristic is an *underestimate*, it's guaranteed to find you the best path. @@ -277,7 +282,7 @@ public final class Settings { /** * Start planning the next path once the remaining movements tick estimates sum up to less than this value */ - public final Setting planningTickLookAhead = new Setting<>(150); + public final Setting planningTickLookahead = new Setting<>(150); /** * Default size of the Long2ObjectOpenHashMap used in pathing @@ -308,6 +313,8 @@ public final class Settings { * Is it okay to sprint through a descend followed by a diagonal? * The player overshoots the landing, but not enough to fall off. And the diagonal ensures that there isn't * lava or anything that's !canWalkInto in that space, so it's technically safe, just a little sketchy. + *

+ * Note: this is *not* related to the allowDiagonalDescend setting, that is a completely different thing. */ public final Setting allowOvershootDiagonalDescend = new Setting<>(true); @@ -378,6 +385,11 @@ public final class Settings { */ public final Setting pruneRegionsFromRAM = new Setting<>(false); + /** + * Cancel baritone on left click, as a form of "panic button" + */ + public final Setting clickCancel = new Setting<>(false); + /** * Remember the contents of containers (chests, echests, furnaces) *

@@ -388,7 +400,7 @@ public final class Settings { /** * Print all the debug messages to chat */ - public final Setting chatDebug = new Setting<>(true); + public final Setting chatDebug = new Setting<>(false); /** * Allow chat based control of Baritone. Most likely should be disabled when Baritone is imported for use in @@ -467,7 +479,18 @@ public final class Settings { public final Setting pathThroughCachedOnly = new Setting<>(false); /** - * 😎 Render cached chunks as semitransparent. Doesn't work with OptiFine 😭 + * Continue sprinting while in water + */ + public final Setting sprintInWater = new Setting<>(true); + + /** + * When GetToBlockProcess fails to calculate a path, instead of just giving up, mark the closest instances + * of that block as "unreachable" and go towards the next closest + */ + public final Setting blacklistOnGetToBlockFailure = new Setting<>(true); + + /** + * 😎 Render cached chunks as semitransparent. Doesn't work with OptiFine 😭 Rarely randomly crashes, see this issue. *

* Can be very useful on servers with low render distance. After enabling, you may need to reload the world in order for it to have an effect * (e.g. disconnect and reconnect, enter then exit the nether, die and respawn, etc). This may literally kill your FPS and CPU because @@ -558,6 +581,19 @@ public final class Settings { */ public final Setting legitMineYLevel = new Setting<>(11); + /** + * Magically see ores that are separated diagonally from existing ores. Basically like mining around the ores that it finds + * in case there's one there touching it diagonally, except it checks it un-legit-ly without having the mine blocks to see it. + * You can decide whether this looks plausible or not. + *

+ * This is disabled because it results in some weird behavior. For example, it can """see""" the top block of a vein of iron_ore + * through a lava lake. This isn't an issue normally since it won't consider anything touching lava, so it just ignores it. + * However, this setting expands that and allows it to see the entire vein so it'll mine under the lava lake to get the iron that + * it can reach without mining blocks adjacent to lava. This really defeats the purpose of legitMine since a player could never + * do that lol, so thats one reason why its disabled + */ + public final Setting legitMineIncludeDiagonals = new Setting<>(false); + /** * When mining block of a certain type, try to mine two at once instead of one. * If the block above is also a goal block, set GoalBlock instead of GoalTwoBlocks diff --git a/src/api/java/baritone/api/utils/Rotation.java b/src/api/java/baritone/api/utils/Rotation.java index 7f93547b..54f63ebf 100644 --- a/src/api/java/baritone/api/utils/Rotation.java +++ b/src/api/java/baritone/api/utils/Rotation.java @@ -117,8 +117,12 @@ public class Rotation { * @return are they really close */ public boolean isReallyCloseTo(Rotation other) { - float yawDiff = Math.abs(this.yaw - other.yaw); // you cant fool me - return (yawDiff < 0.01 || yawDiff > 359.9) && Math.abs(this.pitch - other.pitch) < 0.01; + return yawIsReallyClose(other) && Math.abs(this.pitch - other.pitch) < 0.01; + } + + public boolean yawIsReallyClose(Rotation other) { + float yawDiff = Math.abs(normalizeYaw(yaw) - normalizeYaw(other.yaw)); // you cant fool me + return (yawDiff < 0.01 || yawDiff > 359.99); } /** @@ -147,4 +151,9 @@ public class Rotation { } return newYaw; } + + @Override + public String toString() { + return "Yaw: " + yaw + ", Pitch: " + pitch; + } } diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java index 9352b7fe..3010d283 100644 --- a/src/api/java/baritone/api/utils/RotationUtils.java +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -78,6 +78,9 @@ public final class RotationUtils { * @return The wrapped angles */ public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) { + if (current.yawIsReallyClose(target)) { + return new Rotation(current.getYaw(), target.getPitch()); + } return target.subtract(current).normalize().add(current); } @@ -102,7 +105,7 @@ public final class RotationUtils { * @param dest The destination position * @return The rotation from the origin to the destination */ - public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) { + private static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) { double[] delta = {orig.x - dest.x, orig.y - dest.y, orig.z - dest.z}; double yaw = MathHelper.atan2(delta[0], -delta[2]); double dist = Math.sqrt(delta[0] * delta[0] + delta[2] * delta[2]); @@ -196,7 +199,7 @@ public final class RotationUtils { * @return The optional rotation */ public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) { - Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos); + Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos, new Rotation(entity.rotationYaw, entity.rotationPitch)); RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance); //System.out.println(result); if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) { diff --git a/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java b/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java index fef16d6b..511e1c14 100644 --- a/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java +++ b/src/launch/java/baritone/launch/mixins/MixinChunkRenderContainer.java @@ -22,27 +22,31 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ChunkRenderContainer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL14; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.Redirect; import static org.lwjgl.opengl.GL11.*; @Mixin(ChunkRenderContainer.class) public class MixinChunkRenderContainer { - @Inject( + @Redirect( // avoid creating CallbackInfo at all costs; this is called 40k times per second method = "preRenderChunk", - at = @At("HEAD") + at = @At( + value = "INVOKE", + target = "net/minecraft/client/renderer/chunk/RenderChunk.getPosition()Lnet/minecraft/util/math/BlockPos;" + ) ) - private void preRenderChunk(RenderChunk renderChunkIn, CallbackInfo ci) { + private BlockPos getPosition(RenderChunk renderChunkIn) { if (Baritone.settings().renderCachedChunks.get() && Minecraft.getMinecraft().world.getChunk(renderChunkIn.getPosition()).isEmpty()) { GlStateManager.enableAlpha(); GlStateManager.enableBlend(); GL14.glBlendColor(0, 0, 0, Baritone.settings().cachedChunksOpacity.get()); GlStateManager.tryBlendFuncSeparate(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_ONE, GL_ZERO); } + return renderChunkIn.getPosition(); } } diff --git a/src/launch/java/baritone/launch/mixins/MixinKeyBinding.java b/src/launch/java/baritone/launch/mixins/MixinKeyBinding.java index 9ef080bf..d61537c9 100644 --- a/src/launch/java/baritone/launch/mixins/MixinKeyBinding.java +++ b/src/launch/java/baritone/launch/mixins/MixinKeyBinding.java @@ -20,6 +20,7 @@ package baritone.launch.mixins; import baritone.Baritone; import baritone.api.BaritoneAPI; import baritone.utils.Helper; +import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -61,6 +62,11 @@ public class MixinKeyBinding { private void isPressed(CallbackInfoReturnable cir) { // only the primary baritone forces keys Boolean force = BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this); + if (pressTime > 0 && (KeyBinding) (Object) this == Minecraft.getMinecraft().gameSettings.keyBindAttack && Baritone.settings().clickCancel.get() && BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().isPathing()) { + Helper.HELPER.logDirect("Cancelling path on left click since the clickCancel setting is enabled!"); + BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().cancelEverything(); + return; + } if (force != null && !force && Baritone.settings().suppressClicks.get()) { // <-- cursed if (pressTime > 0) { Helper.HELPER.logDirect("You're trying to press this mouse button but I won't let you."); diff --git a/src/launch/java/baritone/launch/mixins/MixinRenderList.java b/src/launch/java/baritone/launch/mixins/MixinRenderList.java index 55d1da70..3d4d8a91 100644 --- a/src/launch/java/baritone/launch/mixins/MixinRenderList.java +++ b/src/launch/java/baritone/launch/mixins/MixinRenderList.java @@ -22,25 +22,25 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderList; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.Redirect; import static org.lwjgl.opengl.GL11.*; @Mixin(RenderList.class) public class MixinRenderList { - @Inject( + @Redirect( // avoid creating CallbackInfo at all costs; this is called 40k times per second method = "renderChunkLayer", at = @At( value = "INVOKE", target = "net/minecraft/client/renderer/GlStateManager.popMatrix()V" ) ) - private void renderChunkLayer(CallbackInfo info) { + private void popMatrix() { if (Baritone.settings().renderCachedChunks.get()) { // reset the blend func to normal (not dependent on constant alpha) GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } + GlStateManager.popMatrix(); } } diff --git a/src/launch/java/baritone/launch/mixins/MixinVboRenderList.java b/src/launch/java/baritone/launch/mixins/MixinVboRenderList.java index c2c9fd8c..70048c8c 100644 --- a/src/launch/java/baritone/launch/mixins/MixinVboRenderList.java +++ b/src/launch/java/baritone/launch/mixins/MixinVboRenderList.java @@ -22,25 +22,25 @@ import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.VboRenderList; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.Redirect; import static org.lwjgl.opengl.GL11.*; @Mixin(VboRenderList.class) public class MixinVboRenderList { - @Inject( + @Redirect( // avoid creating CallbackInfo at all costs; this is called 40k times per second method = "renderChunkLayer", at = @At( value = "INVOKE", target = "net/minecraft/client/renderer/GlStateManager.popMatrix()V" ) ) - private void renderChunkLayer(CallbackInfo info) { + private void popMatrix() { if (Baritone.settings().renderCachedChunks.get()) { // reset the blend func to normal (not dependent on constant alpha) GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } + GlStateManager.popMatrix(); } } diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 2e8957a6..bc3443a7 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -122,11 +122,27 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, cancelRequested = false; baritone.getInputOverrideHandler().clearAllKeys(); } - if (current == null) { - return; - } - safeToCancel = current.onTick(); synchronized (pathPlanLock) { + synchronized (pathCalcLock) { + if (inProgress != null) { + // we are calculating + // are we calculating the right thing though? 🤔 + BetterBlockPos calcFrom = inProgress.getStart(); + Optional currentBest = inProgress.bestPathSoFar(); + if ((current == null || !current.getPath().getDest().equals(calcFrom)) // if current ends in inProgress's start, then we're ok + && !calcFrom.equals(ctx.playerFeet()) && !calcFrom.equals(expectedSegmentStart) // if current starts in our playerFeet or pathStart, then we're ok + && (!currentBest.isPresent() || (!currentBest.get().positions().contains(ctx.playerFeet()) && !currentBest.get().positions().contains(expectedSegmentStart))) // if + ) { + // when it was *just* started, currentBest will be empty so we need to also check calcFrom since that's always present + inProgress.cancel(); // cancellation doesn't dispatch any events + inProgress = null; // this is safe since we hold both locks + } + } + } + if (current == null) { + return; + } + safeToCancel = current.onTick(); if (current.failed() || current.finished()) { current = null; if (goal == null || goal.isInGoal(ctx.playerFeet())) { @@ -135,7 +151,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, next = null; return; } - if (next != null && !next.getPath().positions().contains(ctx.playerFeet()) && !next.getPath().positions().contains(pathStart())) { // can contain either one + if (next != null && !next.getPath().positions().contains(ctx.playerFeet()) && !next.getPath().positions().contains(expectedSegmentStart)) { // can contain either one // if the current path failed, we may not actually be on the next one, so make sure logDebug("Discarding next path as it does not contain current position"); // for example if we had a nicely planned ahead path that starts where current ends @@ -157,23 +173,12 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, // at this point, current just ended, but we aren't in the goal and have no plan for the future synchronized (pathCalcLock) { if (inProgress != null) { - // we are calculating - // are we calculating the right thing though? 🤔 - BetterBlockPos calcFrom = inProgress.getStart(); - // if current just succeeded, we should be standing in calcFrom, so that's cool and good - // but if current just failed, we should discard this calculation since it doesn't start from where we're standing - if (calcFrom.equals(ctx.playerFeet()) || calcFrom.equals(pathStart())) { - // cool and good - queuePathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING); - return; - } - // oh noes - inProgress.cancel(); // cancellation doesn't dispatch any events - inProgress = null; // this is safe since we hold both locks + queuePathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING); + return; } // we aren't calculating queuePathEvent(PathEvent.CALC_STARTED); - findPathInNewThread(pathStart(), true, context); + findPathInNewThread(expectedSegmentStart, true, context); } return; } @@ -204,7 +209,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, // and this path doesn't get us all the way there return; } - if (ticksRemainingInSegment(false).get() < Baritone.settings().planningTickLookAhead.get()) { + if (ticksRemainingInSegment(false).get() < Baritone.settings().planningTickLookahead.get()) { // and this path has 7.5 seconds or less left // don't include the current movement so a very long last movement (e.g. descend) doesn't trip it up // if we actually included current, it wouldn't start planning ahead until the last movement was done, if the last movement took more than 7.5 seconds on its own @@ -247,8 +252,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, if (goal == null) { return false; } - BlockPos pathStart = pathStart(); - if (goal.isInGoal(ctx.playerFeet()) || goal.isInGoal(pathStart)) { + if (goal.isInGoal(ctx.playerFeet()) || goal.isInGoal(expectedSegmentStart)) { return false; } synchronized (pathPlanLock) { @@ -260,7 +264,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return false; } queuePathEvent(PathEvent.CALC_STARTED); - findPathInNewThread(pathStart, true, context); + findPathInNewThread(expectedSegmentStart, true, context); return true; } } @@ -333,12 +337,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, public void secretInternalSegmentCancel() { queuePathEvent(PathEvent.CANCELED); synchronized (pathPlanLock) { - current = null; - next = null; + if (current != null) { + current = null; + next = null; + baritone.getInputOverrideHandler().clearAllKeys(); + getInProgress().ifPresent(AbstractNodeCostSearch::cancel); + baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock(); + } } - baritone.getInputOverrideHandler().clearAllKeys(); - getInProgress().ifPresent(AbstractNodeCostSearch::cancel); - baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock(); } public void forceCancel() { // NOT exposed on public api @@ -448,7 +454,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, Optional executor = calcResult.getPath().map(p -> new PathExecutor(PathingBehavior.this, p)); if (current == null) { if (executor.isPresent()) { - if (executor.get().getPath().getSrc().equals(expectedSegmentStart)) { + if (executor.get().getPath().positions().contains(expectedSegmentStart)) { queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING); current = executor.get(); } else { @@ -463,8 +469,12 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } else { if (next == null) { if (executor.isPresent()) { - queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_FINISHED); - next = executor.get(); + if (executor.get().getPath().getSrc().equals(current.getPath().getDest())) { + queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_FINISHED); + next = executor.get(); + } else { + logDebug("Warning: discarding orphan next segment with incorrect start"); + } } else { queuePathEvent(PathEvent.NEXT_CALC_FAILED); } diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index 84bac80f..b1bb1182 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -50,7 +50,9 @@ public final class GameEventHandler implements IEventBus, Helper { if (event.getType() == TickEvent.Type.IN) { try { baritone.bsi = new BlockStateInterface(baritone.getPlayerContext(), true); - } catch (Exception ex) {} + } catch (Exception ex) { + baritone.bsi = null; + } } else { baritone.bsi = null; } diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index 4e7eb26f..07ee79aa 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -160,7 +160,7 @@ public abstract class Movement implements IMovement, MovementHelper { //i dont care if theres snow in the way!!!!!!! //you dont own me!!!! state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.player().getPositionEyes(1.0F), - VecUtils.getBlockPosCenter(blockPos)), true) + VecUtils.getBlockPosCenter(blockPos), ctx.playerRotations()), true) ); // don't check selectedblock on this one, this is a fallback when we can't see any face directly, it's intended to be breaking the "incorrect" block state.setInput(Input.CLICK_LEFT, true); diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 437aa2c3..77b59db2 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -407,11 +407,10 @@ public interface MovementHelper extends ActionCosts, Helper { } static void moveTowards(IPlayerContext ctx, MovementState state, BlockPos pos) { - EntityPlayerSP player = ctx.player(); state.setTarget(new MovementTarget( - new Rotation(RotationUtils.calcRotationFromVec3d(player.getPositionEyes(1.0F), + new Rotation(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(pos), - new Rotation(player.rotationYaw, player.rotationPitch)).getYaw(), player.rotationPitch), + ctx.playerRotations()).getYaw(), ctx.player().rotationPitch), false )).setInput(Input.MOVE_FORWARD, true); } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index 69cee856..3a86c158 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -199,7 +199,7 @@ public class MovementAscend extends Movement { return state.setInput(Input.JUMP, true); } - private boolean headBonkClear() { + public boolean headBonkClear() { BetterBlockPos startUp = src.up(2); for (int i = 0; i < 4; i++) { BetterBlockPos check = startUp.offset(EnumFacing.byHorizontalIndex(i)); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index f9a8a343..5e06bc00 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -245,7 +245,7 @@ public class MovementDescend extends Movement { // (dest - src) + dest is offset 1 more in the same direction // so it's the block we'd need to worry about running into if we decide to sprint straight through this descend BlockPos into = dest.subtract(src.down()).add(dest); - if (!MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into)) && MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into).up()) && MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into).up(2))) { + if (skipToAscend()) { // if dest extends into can't walk through, but the two above are can walk through, then we can overshoot and glitch in that weird way return true; } @@ -256,4 +256,9 @@ public class MovementDescend extends Movement { } return false; } + + public boolean skipToAscend() { + BlockPos into = dest.subtract(src.down()).add(dest); + return !MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into)) && MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into).up()) && MovementHelper.canWalkThrough(ctx, new BetterBlockPos(into).up(2)); + } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java index f34e9468..f156ff1b 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java @@ -17,6 +17,7 @@ package baritone.pathing.movement.movements; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.pathing.movement.MovementStatus; import baritone.api.utils.BetterBlockPos; @@ -181,7 +182,7 @@ public class MovementDiagonal extends Movement { } public boolean sprint() { - if (MovementHelper.isLiquid(ctx, ctx.playerFeet())) { + if (MovementHelper.isLiquid(ctx, ctx.playerFeet()) && !Baritone.settings().sprintInWater.get()) { return false; } for (int i = 0; i < 4; i++) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java index 729a2f1d..b0674887 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java @@ -78,7 +78,7 @@ public class MovementFall extends Movement { } BlockPos playerFeet = ctx.playerFeet(); - Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest)); + Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest),ctx.playerRotations()); Rotation targetRotation = null; Block destBlock = ctx.world().getBlockState(dest).getBlock(); boolean isWater = destBlock == Blocks.WATER || destBlock == Blocks.FLOWING_WATER; @@ -141,7 +141,7 @@ public class MovementFall extends Movement { } if (targetRotation == null) { Vec3d destCenterOffset = new Vec3d(destCenter.x + 0.125 * avoid.getX(), destCenter.y, destCenter.z + 0.125 * avoid.getZ()); - state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), destCenterOffset), false)); + state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), destCenterOffset,ctx.playerRotations()), false)); } return state; } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index a9d1e20e..bb94fa30 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -160,7 +160,7 @@ public class MovementPillar extends Movement { IBlockState fromDown = BlockStateInterface.get(ctx, src); if (MovementHelper.isWater(fromDown.getBlock()) && MovementHelper.isWater(ctx, dest)) { // stay centered while swimming up a water column - state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest)), false)); + state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest),ctx.playerRotations()), false)); Vec3d destCenter = VecUtils.getBlockPosCenter(dest); if (Math.abs(ctx.player().posX - destCenter.x) > 0.2 || Math.abs(ctx.player().posZ - destCenter.z) > 0.2) { state.setInput(Input.MOVE_FORWARD, true); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index c3f9892a..fa47ce21 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -175,7 +175,7 @@ public class MovementTraverse extends Movement { // combine the yaw to the center of the destination, and the pitch to the specific block we're trying to break // it's safe to do this since the two blocks we break (in a traverse) are right on top of each other and so will have the same yaw - float yawToDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), dest)).getYaw(); + float yawToDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), dest), ctx.playerRotations()).getYaw(); float pitchToBreak = state.getTarget().getRotation().get().getPitch(); state.setTarget(new MovementState.MovementTarget(new Rotation(yawToDest, pitchToBreak), true)); @@ -199,7 +199,7 @@ public class MovementTraverse extends Movement { isDoorActuallyBlockingUs = true; } if (isDoorActuallyBlockingUs && !(Blocks.IRON_DOOR.equals(pb0.getBlock()) || Blocks.IRON_DOOR.equals(pb1.getBlock()))) { - return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), positionsToBreak[0])), true)) + return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), positionsToBreak[0]), ctx.playerRotations()), true)) .setInput(Input.CLICK_RIGHT, true); } } @@ -213,7 +213,7 @@ public class MovementTraverse extends Movement { } if (blocked != null) { - return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), blocked)), true)) + return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.calculateBlockCenter(ctx.world(), blocked), ctx.playerRotations()), true)) .setInput(Input.CLICK_RIGHT, true); } } @@ -235,7 +235,7 @@ public class MovementTraverse extends Movement { BlockPos into = dest.subtract(src).add(dest); Block intoBelow = BlockStateInterface.get(ctx, into).getBlock(); Block intoAbove = BlockStateInterface.get(ctx, into.up()).getBlock(); - if (wasTheBridgeBlockAlwaysThere && !MovementHelper.isLiquid(ctx, ctx.playerFeet()) && !MovementHelper.avoidWalkingInto(intoBelow) && !MovementHelper.avoidWalkingInto(intoAbove)) { + if (wasTheBridgeBlockAlwaysThere && (!MovementHelper.isLiquid(ctx, ctx.playerFeet()) || Baritone.settings().sprintInWater.get()) && (!MovementHelper.avoidWalkingInto(intoBelow) || MovementHelper.isWater(intoBelow)) && !MovementHelper.avoidWalkingInto(intoAbove)) { state.setInput(Input.SPRINT, true); } Block destDown = BlockStateInterface.get(ctx, dest.down()).getBlock(); diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index 1b59f8e3..1a221af3 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -25,6 +25,7 @@ import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.path.IPathExecutor; import baritone.api.utils.BetterBlockPos; import baritone.api.utils.IPlayerContext; +import baritone.api.utils.RotationUtils; import baritone.api.utils.VecUtils; import baritone.api.utils.input.Input; import baritone.behavior.PathingBehavior; @@ -39,6 +40,8 @@ import net.minecraft.block.BlockLiquid; import net.minecraft.init.Blocks; import net.minecraft.util.Tuple; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import java.util.*; @@ -104,14 +107,6 @@ public class PathExecutor implements IPathExecutor, Helper { BetterBlockPos whereShouldIBe = path.positions().get(pathPosition); BetterBlockPos whereAmI = ctx.playerFeet(); if (!whereShouldIBe.equals(whereAmI)) { - - if (pathPosition == 0 && whereAmI.equals(whereShouldIBe.up()) && Math.abs(ctx.player().motionY) < 0.1 && !(path.movements().get(0) instanceof MovementAscend) && !(path.movements().get(0) instanceof MovementPillar)) { - // avoid the Wrong Y coordinate bug - // TODO add a timer here - new MovementDownward(behavior.baritone, whereAmI, whereShouldIBe).update(); - return false; - } - if (!Blocks.AIR.equals(BlockStateInterface.getBlock(ctx, whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip for (int i = 0; i < pathPosition - 1 && i < path.length(); i++) {//this happens for example when you lag out and get teleported back a couple blocks if (whereAmI.equals(path.positions().get(i))) { @@ -122,6 +117,7 @@ public class PathExecutor implements IPathExecutor, Helper { path.movements().get(j).reset(); } onChangeInPathPosition(); + onTick(); return false; } } @@ -134,6 +130,7 @@ public class PathExecutor implements IPathExecutor, Helper { //System.out.println("Double skip sundae"); pathPosition = i - 1; onChangeInPathPosition(); + onTick(); return false; } } @@ -195,17 +192,17 @@ public class PathExecutor implements IPathExecutor, Helper { continue; } Movement m = (Movement) path.movements().get(i); - HashSet prevBreak = new HashSet<>(m.toBreak(bsi)); - HashSet prevPlace = new HashSet<>(m.toPlace(bsi)); - HashSet prevWalkInto = new HashSet<>(m.toWalkInto(bsi)); + List prevBreak = m.toBreak(bsi); + List prevPlace = m.toPlace(bsi); + List prevWalkInto = m.toWalkInto(bsi); m.resetBlockCache(); - if (!prevBreak.equals(new HashSet<>(m.toBreak(bsi)))) { + if (!prevBreak.equals(m.toBreak(bsi))) { recalcBP = true; } - if (!prevPlace.equals(new HashSet<>(m.toPlace(bsi)))) { + if (!prevPlace.equals(m.toPlace(bsi))) { recalcBP = true; } - if (!prevWalkInto.equals(new HashSet<>(m.toWalkInto(bsi)))) { + if (!prevWalkInto.equals(m.toWalkInto(bsi))) { recalcBP = true; } } @@ -388,17 +385,34 @@ public class PathExecutor implements IPathExecutor, Helper { if (!new CalculationContext(behavior.baritone).canSprint) { return false; } + IMovement current = path.movements().get(pathPosition); + + // traverse requests sprinting, so we need to do this check first + if (current instanceof MovementTraverse && pathPosition < path.length() - 3) { + IMovement next = path.movements().get(pathPosition + 1); + if (next instanceof MovementAscend && sprintableAscend(ctx, (MovementTraverse) current, (MovementAscend) next, path.movements().get(pathPosition + 2))) { + if (skipNow(ctx, current, next)) { + logDebug("Skipping traverse to straight ascend"); + pathPosition++; + onChangeInPathPosition(); + onTick(); + behavior.baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, true); + return true; + } else { + logDebug("Too far to the side to safely sprint ascend"); + } + } + } // if the movement requested sprinting, then we're done if (requested) { return true; } - // however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it - IMovement current = path.movements().get(pathPosition); + // however, descend and ascend don't request sprinting, because they don't know the context of what movement comes after it if (current instanceof MovementDescend) { - if (((MovementDescend) current).safeMode()) { + if (((MovementDescend) current).safeMode() && !((MovementDescend) current).skipToAscend()) { logDebug("Sprinting would be unsafe"); return false; } @@ -408,11 +422,13 @@ public class PathExecutor implements IPathExecutor, Helper { if (next instanceof MovementAscend && current.getDirection().up().equals(next.getDirection().down())) { // a descend then an ascend in the same direction pathPosition++; + onChangeInPathPosition(); + onTick(); // okay to skip clearKeys and / or onChangeInPathPosition here since this isn't possible to repeat, since it's asymmetric logDebug("Skipping descend to straight ascend"); return true; } - if (canSprintInto(ctx, current, next)) { + if (canSprintFromDescendInto(ctx, current, next)) { if (ctx.playerFeet().equals(current.getDest())) { pathPosition++; onChangeInPathPosition(); @@ -432,11 +448,117 @@ public class PathExecutor implements IPathExecutor, Helper { return true; } } + if (pathPosition < path.length() - 2 && prev instanceof MovementTraverse && sprintableAscend(ctx, (MovementTraverse) prev, (MovementAscend) current, path.movements().get(pathPosition + 1))) { + return true; + } + } + if (current instanceof MovementFall) { + Tuple data = overrideFall((MovementFall) current); + if (data != null) { + BlockPos fallDest = data.getSecond(); + if (!path.positions().contains(fallDest)) { + throw new IllegalStateException(); + } + if (ctx.playerFeet().equals(fallDest)) { + pathPosition = path.positions().indexOf(fallDest); + onChangeInPathPosition(); + onTick(); + return true; + } + clearKeys(); + behavior.baritone.getLookBehavior().updateTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), data.getFirst(), ctx.playerRotations()), false); + behavior.baritone.getInputOverrideHandler().setInputForceState(Input.MOVE_FORWARD, true); + return true; + } } return false; } - private static boolean canSprintInto(IPlayerContext ctx, IMovement current, IMovement next) { + private Tuple overrideFall(MovementFall movement) { + Vec3i dir = movement.getDirection(); + if (dir.getY() < -3) { + return null; + } + Vec3i flatDir = new Vec3i(dir.getX(), 0, dir.getZ()); + int i; + outer: + for (i = pathPosition + 1; i < path.length() - 1 && i < pathPosition + 3; i++) { + IMovement next = path.movements().get(i); + if (!(next instanceof MovementTraverse)) { + break; + } + if (!flatDir.equals(next.getDirection())) { + break; + } + for (int y = next.getDest().y; y <= movement.getSrc().y + 1; y++) { + BlockPos chk = new BlockPos(next.getDest().x, y, next.getDest().z); + if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) { + break outer; + } + } + if (!MovementHelper.canWalkOn(ctx, next.getDest().down())) { + break; + } + } + i--; + if (i == pathPosition) { + return null; // no valid extension exists + } + double len = i - pathPosition - 0.4; + return new Tuple<>( + new Vec3d(flatDir.getX() * len + movement.getDest().x + 0.5, movement.getDest().y, flatDir.getZ() * len + movement.getDest().z + 0.5), + movement.getDest().add(flatDir.getX() * (i - pathPosition), 0, flatDir.getZ() * (i - pathPosition))); + } + + private static boolean skipNow(IPlayerContext ctx, IMovement current, IMovement next) { + double offTarget = Math.abs(current.getDirection().getX() * (current.getSrc().z + 0.5D - ctx.player().posZ)) + Math.abs(current.getDirection().getZ() * (current.getSrc().x + 0.5D - ctx.player().posX)); + if (offTarget > 0.1) { + return false; + } + // we are centered + BlockPos headBonk = current.getSrc().subtract(current.getDirection()).up(2); + if (MovementHelper.fullyPassable(ctx.world().getBlockState(headBonk))) { + return true; + } + // wait 0.3 + double flatDist = Math.abs(current.getDirection().getX() * (headBonk.getX() + 0.5D - ctx.player().posX)) + Math.abs(current.getDirection().getZ() * (headBonk.getZ() + 0.5 - ctx.player().posZ)); + return flatDist > 0.8; + } + + private static boolean sprintableAscend(IPlayerContext ctx, MovementTraverse current, MovementAscend next, IMovement nextnext) { + if (!Baritone.settings().sprintAscends.get()) { + return false; + } + if (!current.getDirection().equals(next.getDirection().down())) { + return false; + } + if (nextnext.getDirection().getX() != next.getDirection().getX() || nextnext.getDirection().getZ() != next.getDirection().getZ()) { + return false; + } + if (!MovementHelper.canWalkOn(ctx, current.getDest().down())) { + return false; + } + for (int x = 0; x < 2; x++) { + for (int y = 0; y < 3; y++) { + BlockPos chk = current.getSrc().up(y); + if (x == 1) { + chk = chk.add(current.getDirection()); + } + if (!MovementHelper.fullyPassable(ctx.world().getBlockState(chk))) { + return false; + } + } + } + if (MovementHelper.avoidWalkingInto(ctx.world().getBlockState(current.getSrc().up(3)).getBlock())) { + return false; + } + if (MovementHelper.avoidWalkingInto(ctx.world().getBlockState(next.getDest().up(2)).getBlock())) { + return false; + } + return true; + } + + private static boolean canSprintFromDescendInto(IPlayerContext ctx, IMovement current, IMovement next) { if (next instanceof MovementDescend && next.getDirection().equals(current.getDirection())) { return true; } diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 351f0253..3db08d57 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -202,7 +202,7 @@ public class BuilderProcess extends BaritoneProcessHelper implements IBuilderPro double placeX = placeAgainstPos.x + aabb.minX * placementMultiplier.x + aabb.maxX * (1 - placementMultiplier.x); double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y); double placeZ = placeAgainstPos.z + aabb.minZ * placementMultiplier.z + aabb.maxZ * (1 - placementMultiplier.z); - Rotation rot = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(placeX, placeY, placeZ)); + Rotation rot = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(placeX, placeY, placeZ), ctx.playerRotations()); RayTraceResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot, ctx.playerController().getBlockReachDistance()); if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK && result.getBlockPos().equals(placeAgainstPos) && result.sideHit == against.getOpposite()) { OptionalInt hotbar = hasAnyItemThatWouldPlace(toPlace, result, rot); diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index c3ac0616..7796c029 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -32,15 +32,13 @@ import net.minecraft.init.Blocks; import net.minecraft.inventory.ContainerPlayer; import net.minecraft.util.math.BlockPos; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess { private Block gettingTo; private List knownLocations; + private List blacklist; // locations we failed to calc to private BlockPos start; private int tickCount = 0; @@ -54,6 +52,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl onLostControl(); gettingTo = block; start = ctx.playerFeet(); + blacklist = new ArrayList<>(); rescan(new ArrayList<>(), new CalculationContext(baritone)); } @@ -63,12 +62,12 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl } @Override - public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + public synchronized PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (knownLocations == null) { rescan(new ArrayList<>(), new CalculationContext(baritone)); } if (knownLocations.isEmpty()) { - if (Baritone.settings().exploreForBlocks.get()) { + if (Baritone.settings().exploreForBlocks.get() && !calcFailed) { return new PathingCommand(new GoalRunAway(1, start) { @Override public boolean isInGoal(int x, int y, int z) { @@ -82,12 +81,19 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl } return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } + Goal goal = new GoalComposite(knownLocations.stream().map(this::createGoal).toArray(Goal[]::new)); if (calcFailed) { - logDirect("Unable to find any path to " + gettingTo + ", canceling GetToBlock"); - if (isSafeToCancel) { - onLostControl(); + if (Baritone.settings().blacklistOnGetToBlockFailure.get()) { + logDirect("Unable to find any path to " + gettingTo + ", blacklisting presumably unreachable closest instances"); + blacklistClosest(); + return onTick(false, isSafeToCancel); // gamer moment + } else { + logDirect("Unable to find any path to " + gettingTo + ", canceling GetToBlock"); + if (isSafeToCancel) { + onLostControl(); + } + return new PathingCommand(goal, PathingCommandType.CANCEL_AND_SET_GOAL); } - return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain @@ -95,25 +101,58 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl CalculationContext context = new CalculationContext(baritone, true); Baritone.getExecutor().execute(() -> rescan(current, context)); } - Goal goal = new GoalComposite(knownLocations.stream().map(this::createGoal).toArray(Goal[]::new)); if (goal.isInGoal(ctx.playerFeet()) && isSafeToCancel) { // we're there if (rightClickOnArrival(gettingTo)) { if (rightClick()) { onLostControl(); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } } else { onLostControl(); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } } return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); } + // blacklist the closest block and its adjacent blocks + public synchronized void blacklistClosest() { + List newBlacklist = new ArrayList<>(); + knownLocations.stream().min(Comparator.comparingDouble(ctx.player()::getDistanceSq)).ifPresent(newBlacklist::add); + outer: + while (true) { + for (BlockPos known : knownLocations) { + for (BlockPos blacklist : newBlacklist) { + if (areAdjacent(known, blacklist)) { // directly adjacent + newBlacklist.add(known); + knownLocations.remove(known); + continue outer; + } + } + } + if (true) { + break; // codacy gets mad if i just end on a break LOL + } + } + logDebug("Blacklisting unreachable locations " + newBlacklist); + blacklist.addAll(newBlacklist); + } + + // safer than direct double comparison from distanceSq + private boolean areAdjacent(BlockPos posA, BlockPos posB) { + int diffX = Math.abs(posA.getX() - posB.getX()); + int diffY = Math.abs(posA.getY() - posB.getY()); + int diffZ = Math.abs(posA.getZ() - posB.getZ()); + return (diffX + diffY + diffZ) == 1; + } + @Override - public void onLostControl() { + public synchronized void onLostControl() { gettingTo = null; knownLocations = null; start = null; + blacklist = null; baritone.getInputOverrideHandler().clearAllKeys(); } @@ -122,8 +161,10 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl return "Get To Block " + gettingTo; } - private void rescan(List known, CalculationContext context) { - knownLocations = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known); + private synchronized void rescan(List known, CalculationContext context) { + List positions = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known); + positions.removeIf(blacklist::contains); + knownLocations = positions; } private Goal createGoal(BlockPos pos) { diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 80677456..a299bf31 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -228,7 +228,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return prune(ctx, locs, mining, max); } - public void addNearby() { + private void addNearby() { knownOreLocations.addAll(droppedItemsScan(mining, ctx.world())); BlockPos playerFeet = ctx.playerFeet(); BlockStateInterface bsi = new BlockStateInterface(ctx); @@ -239,8 +239,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro for (int z = playerFeet.getZ() - searchDist; z <= playerFeet.getZ() + searchDist; z++) { // crucial to only add blocks we can see because otherwise this // is an x-ray and it'll get caught - if (mining.contains(bsi.get0(x, y, z).getBlock()) && RotationUtils.reachable(ctx.player(), new BlockPos(x, y, z), fakedBlockReachDistance).isPresent()) { - knownOreLocations.add(new BlockPos(x, y, z)); + if (mining.contains(bsi.get0(x, y, z).getBlock())) { + BlockPos pos = new BlockPos(x, y, z); + if ((Baritone.settings().legitMineIncludeDiagonals.get() && knownOreLocations.stream().anyMatch(ore -> ore.distanceSq(pos) <= 2 /* sq means this is pytha dist <= sqrt(2) */)) || RotationUtils.reachable(ctx.player(), pos, fakedBlockReachDistance).isPresent()) { + knownOreLocations.add(pos); + } } } } @@ -250,12 +253,19 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public static List prune(CalculationContext ctx, List locs2, List mining, int max) { List dropped = droppedItemsScan(mining, ctx.world); + dropped.removeIf(drop -> { + for (BlockPos pos : locs2) { + if (pos.distanceSq(drop) <= 9 && mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) && MineProcess.plausibleToBreak(ctx.bsi, pos)) { // TODO maybe drop also has to be supported? no lava below? + return true; + } + } + return false; + }); List locs = locs2 .stream() .distinct() // remove any that are within loaded chunks that aren't actually what we want - .filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos)) // remove any that are implausible to mine (encased in bedrock, or touching lava) diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index 68c9eae1..e9dbb726 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -164,36 +164,19 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } if (msg.startsWith("goal")) { - String[] params = msg.substring(4).trim().split(" "); - if (params[0].equals("")) { - params = new String[]{}; - } + String rest = msg.substring(4).trim(); Goal goal; - try { - switch (params.length) { - case 0: - goal = new GoalBlock(ctx.playerFeet()); - break; - case 1: - if (params[0].equals("clear") || params[0].equals("none")) { - goal = null; - } else { - goal = new GoalYLevel(Integer.parseInt(params[0])); - } - break; - case 2: - goal = new GoalXZ(Integer.parseInt(params[0]), Integer.parseInt(params[1])); - break; - case 3: - goal = new GoalBlock(new BlockPos(Integer.parseInt(params[0]), Integer.parseInt(params[1]), Integer.parseInt(params[2]))); - break; - default: - logDirect("unable to understand lol"); - return true; + if (rest.equals("clear") || rest.equals("none")) { + goal = null; + } else { + String[] params = rest.split(" "); + if (params[0].equals("")) { + params = new String[]{}; + } + goal = parseGoal(params); + if (goal == null) { + return true; } - } catch (NumberFormatException ex) { - logDirect("unable to parse integer " + ex); - return true; } customGoalProcess.setGoal(goal); logDirect("Goal: " + goal); @@ -270,7 +253,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect(success ? "Loaded" : "Unable to load"); return true; } - if (msg.equals("axis")) { + if (msg.equals("axis") || msg.equals("highway")) { customGoalProcess.setGoalAndPath(new GoalAxis()); return true; } @@ -516,7 +499,11 @@ public class ExampleBaritoneControl extends Behavior implements Helper { if (block == null) { waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getAllWaypoints().stream().filter(w -> w.getName().equalsIgnoreCase(mining)).max(Comparator.comparingLong(IWaypoint::getCreationTimestamp)).orElse(null); if (waypoint == null) { - logDirect("No locations for " + mining + " known, cancelling"); + Goal goal = parseGoal(waypointType.split(" ")); + if (goal != null) { + logDirect("Going to " + goal); + customGoalProcess.setGoalAndPath(goal); + } return true; } } else { @@ -595,4 +582,31 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } } } + + private Goal parseGoal(String[] params) { + Goal goal; + try { + switch (params.length) { + case 0: + goal = new GoalBlock(ctx.playerFeet()); + break; + case 1: + goal = new GoalYLevel(Integer.parseInt(params[0])); + break; + case 2: + goal = new GoalXZ(Integer.parseInt(params[0]), Integer.parseInt(params[1])); + break; + case 3: + goal = new GoalBlock(new BlockPos(Integer.parseInt(params[0]), Integer.parseInt(params[1]), Integer.parseInt(params[2]))); + break; + default: + logDirect("unable to understand lol"); + return null; + } + } catch (NumberFormatException ex) { + logDirect("unable to parse integer " + ex); + return null; + } + return goal; + } } diff --git a/src/main/java/baritone/utils/InputOverrideHandler.java b/src/main/java/baritone/utils/InputOverrideHandler.java index 00d7e16f..925c2bf9 100755 --- a/src/main/java/baritone/utils/InputOverrideHandler.java +++ b/src/main/java/baritone/utils/InputOverrideHandler.java @@ -115,7 +115,7 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri ctx.player().movementInput = new PlayerMovementInput(this); } } else { - if (ctx.player().movementInput.getClass() == PlayerMovementInput.class) { + if (ctx.player().movementInput.getClass() == PlayerMovementInput.class) { // allow other movement inputs that aren't this one, e.g. for a freecam ctx.player().movementInput = new MovementInputFromOptions(Minecraft.getMinecraft().gameSettings); } }