diff --git a/README.md b/README.md index 2cabfd77..445d34bb 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,15 @@ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade) [![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues) +[![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2) -A Minecraft pathfinder bot. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), -the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). +A Minecraft pathfinder bot. Baritone is the pathfinding system used in [Impact](https://impactdevelopment.github.io/) since 4.4. There's a [showcase video](https://www.youtube.com/watch?v=yI8hgW_m6dQ) made by @Adovin#3153 on Baritone's integration into Impact. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a video I made showing off what it can do. +This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), +the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). + Here are some links to help to get started: - [Features](FEATURES.md) @@ -21,29 +24,29 @@ There's also some useful information down below # Setup -## IntelliJ's Gradle UI -- Open the project in IntelliJ as a Gradle project -- Run the Gradle task `setupDecompWorkspace` -- Run the Gradle task `genIntellijRuns` -- Refresh the Gradle project (or just restart IntelliJ) -- Select the "Minecraft Client" launch config and run - ## Command Line On Mac OSX and Linux, use `./gradlew` instead of `gradlew`. Running Baritone: ``` -$ gradlew run +$ gradlew runClient ``` -Setting up for IntelliJ: +Building Baritone: ``` -$ gradlew setupDecompWorkspace -$ gradlew --refresh-dependencies -$ gradlew genIntellijRuns +$ gradlew build ``` +For example, to replace out Impact 4.4's Baritone build with a customized one, switch to the `impact4.4-compat` branch, build Baritone as above then copy `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.0.0/baritone-api-1.0.0.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.4/1.12.2-Impact_4.4.json`, find the line `"name": "cabaletta:baritone-api:1.0.0"`, remove the comma from the end, and entirely remove the line that's immediately after (starts with `"url"`). + +## IntelliJ's Gradle UI +- Open the project in IntelliJ as a Gradle project +- Run the Gradle tasks `setupDecompWorkspace` then `genIntellijRuns` +- Refresh the Gradle project (or, to be safe, just restart IntelliJ) +- Select the "Minecraft Client" launch config +- In `Edit Configurations...` you may need to select `baritone_launch` for `Use classpath of module:`. + # Chat control [Defined Here](src/main/java/baritone/utils/ExampleBaritoneControl.java) diff --git a/build.gradle b/build.gradle index 0e0e3fa2..6b97128a 100755 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,7 @@ sourceSets { minecraft { version = '1.12.2' - mappings = 'snapshot_20180731' + mappings = 'stable_39' tweakClass = 'baritone.launch.BaritoneTweaker' runDir = 'run' diff --git a/src/api/java/baritone/api/BaritoneAPI.java b/src/api/java/baritone/api/BaritoneAPI.java index 0ffd1e98..b9dbcd04 100644 --- a/src/api/java/baritone/api/BaritoneAPI.java +++ b/src/api/java/baritone/api/BaritoneAPI.java @@ -17,10 +17,16 @@ package baritone.api; -import baritone.api.behavior.*; +import baritone.api.behavior.ILookBehavior; +import baritone.api.behavior.IMemoryBehavior; +import baritone.api.behavior.IPathingBehavior; import baritone.api.cache.IWorldProvider; import baritone.api.cache.IWorldScanner; import baritone.api.event.listener.IGameEventListener; +import baritone.api.process.ICustomGoalProcess; +import baritone.api.process.IFollowProcess; +import baritone.api.process.IGetToBlockProcess; +import baritone.api.process.IMineProcess; import baritone.api.utils.SettingsUtil; import java.util.Iterator; @@ -36,20 +42,20 @@ import java.util.ServiceLoader; */ public final class BaritoneAPI { - private static final IBaritoneProvider baritone; + private static final IBaritone baritone; private static final Settings settings; static { ServiceLoader baritoneLoader = ServiceLoader.load(IBaritoneProvider.class); Iterator instances = baritoneLoader.iterator(); - baritone = instances.next(); + baritone = instances.next().getBaritoneForPlayer(null); // PWNAGE settings = new Settings(); SettingsUtil.readAndApply(settings); } - public static IFollowBehavior getFollowBehavior() { - return baritone.getFollowBehavior(); + public static IFollowProcess getFollowProcess() { + return baritone.getFollowProcess(); } public static ILookBehavior getLookBehavior() { @@ -60,8 +66,8 @@ public final class BaritoneAPI { return baritone.getMemoryBehavior(); } - public static IMineBehavior getMineBehavior() { - return baritone.getMineBehavior(); + public static IMineProcess getMineProcess() { + return baritone.getMineProcess(); } public static IPathingBehavior getPathingBehavior() { @@ -80,6 +86,14 @@ public final class BaritoneAPI { return baritone.getWorldScanner(); } + public static ICustomGoalProcess getCustomGoalProcess() { + return baritone.getCustomGoalProcess(); + } + + public static IGetToBlockProcess getGetToBlockProcess() { + return baritone.getGetToBlockProcess(); + } + public static void registerEventListener(IGameEventListener listener) { baritone.registerEventListener(listener); } diff --git a/src/api/java/baritone/api/IBaritone.java b/src/api/java/baritone/api/IBaritone.java new file mode 100644 index 00000000..aee9dead --- /dev/null +++ b/src/api/java/baritone/api/IBaritone.java @@ -0,0 +1,89 @@ +/* + * 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 . + */ + +package baritone.api; + +import baritone.api.behavior.ILookBehavior; +import baritone.api.behavior.IMemoryBehavior; +import baritone.api.behavior.IPathingBehavior; +import baritone.api.cache.IWorldProvider; +import baritone.api.cache.IWorldScanner; +import baritone.api.event.listener.IGameEventListener; +import baritone.api.process.ICustomGoalProcess; +import baritone.api.process.IFollowProcess; +import baritone.api.process.IGetToBlockProcess; +import baritone.api.process.IMineProcess; + +/** + * @author Brady + * @since 9/29/2018 + */ +public interface IBaritone { + + /** + * @return The {@link IFollowProcess} instance + * @see IFollowProcess + */ + IFollowProcess getFollowProcess(); + + /** + * @return The {@link ILookBehavior} instance + * @see ILookBehavior + */ + ILookBehavior getLookBehavior(); + + /** + * @return The {@link IMemoryBehavior} instance + * @see IMemoryBehavior + */ + IMemoryBehavior getMemoryBehavior(); + + /** + * @return The {@link IMineProcess} instance + * @see IMineProcess + */ + IMineProcess getMineProcess(); + + /** + * @return The {@link IPathingBehavior} instance + * @see IPathingBehavior + */ + IPathingBehavior getPathingBehavior(); + + /** + * @return The {@link IWorldProvider} instance + * @see IWorldProvider + */ + IWorldProvider getWorldProvider(); + + /** + * @return The {@link IWorldScanner} instance + * @see IWorldScanner + */ + IWorldScanner getWorldScanner(); + + ICustomGoalProcess getCustomGoalProcess(); + + IGetToBlockProcess getGetToBlockProcess(); + + /** + * Registers a {@link IGameEventListener} with Baritone's "event bus". + * + * @param listener The listener + */ + void registerEventListener(IGameEventListener listener); +} diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java index 88c4adff..745842ce 100644 --- a/src/api/java/baritone/api/IBaritoneProvider.java +++ b/src/api/java/baritone/api/IBaritoneProvider.java @@ -17,70 +17,19 @@ package baritone.api; -import baritone.api.behavior.*; -import baritone.api.cache.IWorldProvider; -import baritone.api.cache.IWorldScanner; -import baritone.api.event.listener.IGameEventListener; +import net.minecraft.client.entity.EntityPlayerSP; /** - * @author Brady - * @since 9/29/2018 + * @author Leijurv */ public interface IBaritoneProvider { /** - * @see IFollowBehavior + * Provides the {@link IBaritone} instance for a given {@link EntityPlayerSP}. This will likely be + * replaced with {@code #getBaritoneForUser(IBaritoneUser)} when {@code bot-system} is merged. * - * @return The {@link IFollowBehavior} instance + * @param player The player + * @return The {@link IBaritone} instance. */ - IFollowBehavior getFollowBehavior(); - - /** - * @see ILookBehavior - * - * @return The {@link ILookBehavior} instance - */ - ILookBehavior getLookBehavior(); - - /** - * @see IMemoryBehavior - * - * @return The {@link IMemoryBehavior} instance - */ - IMemoryBehavior getMemoryBehavior(); - - /** - * @see IMineBehavior - * - * @return The {@link IMineBehavior} instance - */ - IMineBehavior getMineBehavior(); - - /** - * @see IPathingBehavior - * - * @return The {@link IPathingBehavior} instance - */ - IPathingBehavior getPathingBehavior(); - - /** - * @see IWorldProvider - * - * @return The {@link IWorldProvider} instance - */ - IWorldProvider getWorldProvider(); - - /** - * @see IWorldScanner - * - * @return The {@link IWorldScanner} instance - */ - IWorldScanner getWorldScanner(); - - /** - * Registers a {@link IGameEventListener} with Baritone's "event bus". - * - * @param listener The listener - */ - void registerEventListener(IGameEventListener listener); + IBaritone getBaritoneForPlayer(EntityPlayerSP player); } diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 0d8529dd..7fce0254 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -24,8 +24,8 @@ import net.minecraft.util.text.ITextComponent; import java.awt.*; import java.lang.reflect.Field; -import java.util.List; import java.util.*; +import java.util.List; import java.util.function.Consumer; /** @@ -276,6 +276,13 @@ public class Settings { */ public Setting chunkCaching = new Setting<>(true); + /** + * On save, delete from RAM any cached regions that are more than 1024 blocks away from the player + *

+ * Temporarily disabled, see issue #248 + */ + public Setting pruneRegionsFromRAM = new Setting<>(false); + /** * Print all the debug messages to chat */ @@ -305,17 +312,17 @@ public class Settings { /** * Ignore depth when rendering the goal */ - public Setting renderGoalIgnoreDepth = new Setting<>(false); + public Setting renderGoalIgnoreDepth = new Setting<>(true); /** * Ignore depth when rendering the selection boxes (to break, to place, to walk into) */ - public Setting renderSelectionBoxesIgnoreDepth = new Setting<>(false); + public Setting renderSelectionBoxesIgnoreDepth = new Setting<>(true); /** * Ignore depth when rendering the path */ - public Setting renderPathIgnoreDepth = new Setting<>(false); + public Setting renderPathIgnoreDepth = new Setting<>(true); /** * Line width of the path when rendered, in pixels @@ -370,12 +377,27 @@ public class Settings { */ public Setting walkWhileBreaking = new Setting<>(true); + /** + * If we are more than 500 movements into the current path, discard the oldest segments, as they are no longer useful + */ + public Setting maxPathHistoryLength = new Setting<>(300); + + /** + * If the current path is too long, cut off this many movements from the beginning. + */ + public Setting pathHistoryCutoffAmount = new Setting<>(50); + /** * Rescan for the goal once every 5 ticks. * Set to 0 to disable. */ public Setting mineGoalUpdateInterval = new Setting<>(5); + /** + * While mining, should it also consider dropped items of the correct type as a pathing destination (as well as ore blocks)? + */ + public Setting mineScanDroppedItems = new Setting<>(true); + /** * Cancel the current path if the goal has changed, and the path originally ended in the goal but doesn't anymore. *

@@ -389,7 +411,7 @@ public class Settings { *

* Also on cosmic prisons this should be set to true since you don't actually mine the ore it just gets replaced with stone. */ - public Setting cancelOnGoalInvalidation = new Setting<>(false); + public Setting cancelOnGoalInvalidation = new Setting<>(true); /** * The "axis" command (aka GoalAxis) will go to a axis, or diagonal axis, at this Y level. diff --git a/src/api/java/baritone/api/behavior/IBehavior.java b/src/api/java/baritone/api/behavior/IBehavior.java index aee144e2..248148e7 100644 --- a/src/api/java/baritone/api/behavior/IBehavior.java +++ b/src/api/java/baritone/api/behavior/IBehavior.java @@ -18,10 +18,9 @@ package baritone.api.behavior; import baritone.api.event.listener.AbstractGameEventListener; -import baritone.api.utils.interfaces.Toggleable; /** * @author Brady * @since 9/23/2018 */ -public interface IBehavior extends AbstractGameEventListener, Toggleable {} +public interface IBehavior extends AbstractGameEventListener {} diff --git a/src/api/java/baritone/api/behavior/ILookBehavior.java b/src/api/java/baritone/api/behavior/ILookBehavior.java index b5b5d63b..058a5dd8 100644 --- a/src/api/java/baritone/api/behavior/ILookBehavior.java +++ b/src/api/java/baritone/api/behavior/ILookBehavior.java @@ -33,7 +33,7 @@ public interface ILookBehavior extends IBehavior { * otherwise, it should be {@code false}; * * @param rotation The target rotations - * @param force Whether or not to "force" the rotations + * @param force Whether or not to "force" the rotations */ void updateTarget(Rotation rotation, boolean force); } diff --git a/src/api/java/baritone/api/behavior/IPathingBehavior.java b/src/api/java/baritone/api/behavior/IPathingBehavior.java index 7d88ae59..e9ebe405 100644 --- a/src/api/java/baritone/api/behavior/IPathingBehavior.java +++ b/src/api/java/baritone/api/behavior/IPathingBehavior.java @@ -39,35 +39,25 @@ public interface IPathingBehavior extends IBehavior { */ Optional ticksRemainingInSegment(); - /** - * Sets the pathing goal. - * - * @param goal The pathing goal - */ - void setGoal(Goal goal); - /** * @return The current pathing goal */ Goal getGoal(); - /** - * Begins pathing. Calculation will start in a new thread, and once completed, - * movement will commence. Returns whether or not the operation was successful. - * - * @return Whether or not the operation was successful - */ - boolean path(); - /** * @return Whether or not a path is currently being executed. */ boolean isPathing(); /** - * Cancels the pathing behavior or the current path calculation. + * Cancels the pathing behavior or the current path calculation, and all processes that could be controlling path. + *

+ * Basically, "MAKE IT STOP". + * + * @return Whether or not the pathing behavior was canceled. All processes are guaranteed to be canceled, but the + * PathingBehavior might be in the middle of an uncancelable action like a parkour jump */ - void cancel(); + boolean cancelEverything(); /** * Returns the current path, from the current path executor, if there is one. diff --git a/src/api/java/baritone/api/cache/ICachedRegion.java b/src/api/java/baritone/api/cache/ICachedRegion.java index 5f9199fa..6b9048a5 100644 --- a/src/api/java/baritone/api/cache/ICachedRegion.java +++ b/src/api/java/baritone/api/cache/ICachedRegion.java @@ -29,11 +29,10 @@ public interface ICachedRegion extends IBlockTypeAccess { * however, the block coordinates should in on a scale from 0 to 511 (inclusive) * because region sizes are 512x512 blocks. * - * @see ICachedWorld#isCached(int, int) - * * @param blockX The block X coordinate * @param blockZ The block Z coordinate * @return Whether or not the specified XZ location is cached + * @see ICachedWorld#isCached(int, int) */ boolean isCached(int blockX, int blockZ); diff --git a/src/api/java/baritone/api/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java index f8196ebb..5e06a475 100644 --- a/src/api/java/baritone/api/cache/ICachedWorld.java +++ b/src/api/java/baritone/api/cache/ICachedWorld.java @@ -61,8 +61,8 @@ public interface ICachedWorld { * information that is returned by this method may not be up to date, because * older cached chunks can contain data that is much more likely to have changed. * - * @param block The special block to search for - * @param maximum The maximum number of position results to receive + * @param block The special block to search for + * @param maximum The maximum number of position results to receive * @param maxRegionDistanceSq The maximum region distance, squared * @return The locations found that match the special block */ diff --git a/src/api/java/baritone/api/cache/IWaypointCollection.java b/src/api/java/baritone/api/cache/IWaypointCollection.java index 051b199e..4dd80a3e 100644 --- a/src/api/java/baritone/api/cache/IWaypointCollection.java +++ b/src/api/java/baritone/api/cache/IWaypointCollection.java @@ -50,19 +50,17 @@ public interface IWaypointCollection { /** * Gets all of the waypoints that have the specified tag * - * @see IWaypointCollection#getAllWaypoints() - * * @param tag The tag * @return All of the waypoints with the specified tag + * @see IWaypointCollection#getAllWaypoints() */ Set getByTag(IWaypoint.Tag tag); /** * Gets all of the waypoints in this collection, regardless of the tag. * - * @see IWaypointCollection#getByTag(IWaypoint.Tag) - * * @return All of the waypoints in this collection + * @see IWaypointCollection#getByTag(IWaypoint.Tag) */ Set getAllWaypoints(); } diff --git a/src/api/java/baritone/api/event/events/RotationMoveEvent.java b/src/api/java/baritone/api/event/events/RotationMoveEvent.java index 7a7514db..790318e0 100644 --- a/src/api/java/baritone/api/event/events/RotationMoveEvent.java +++ b/src/api/java/baritone/api/event/events/RotationMoveEvent.java @@ -17,7 +17,6 @@ package baritone.api.event.events; -import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.ManagedPlayerEvent; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.entity.Entity; @@ -35,21 +34,30 @@ public final class RotationMoveEvent extends ManagedPlayerEvent { private final Type type; /** - * The state of the event + * The yaw rotation */ - private final EventState state; + private float yaw; - public RotationMoveEvent(EntityPlayerSP player, EventState state, Type type) { + public RotationMoveEvent(EntityPlayerSP player, Type type, float yaw) { super(player); - this.state = state; this.type = type; + this.yaw = yaw; } /** - * @return The state of the event + * Set the yaw movement rotation + * + * @param yaw Yaw rotation */ - public final EventState getState() { - return this.state; + public final void setYaw(float yaw) { + this.yaw = yaw; + } + + /** + * @return The yaw rotation + */ + public final float getYaw() { + return this.yaw; } /** diff --git a/src/api/java/baritone/api/event/events/type/EventState.java b/src/api/java/baritone/api/event/events/type/EventState.java index 10b633bd..072e12c1 100644 --- a/src/api/java/baritone/api/event/events/type/EventState.java +++ b/src/api/java/baritone/api/event/events/type/EventState.java @@ -24,14 +24,12 @@ package baritone.api.event.events.type; public enum EventState { /** - * Indicates that whatever movement the event is being - * dispatched as a result of is about to occur. + * Before the dispatching of what the event is targetting */ PRE, /** - * Indicates that whatever movement the event is being - * dispatched as a result of has already occurred. + * After the dispatching of what the event is targetting */ POST } diff --git a/src/api/java/baritone/api/pathing/calc/IPath.java b/src/api/java/baritone/api/pathing/calc/IPath.java index c9d58818..0844ab90 100644 --- a/src/api/java/baritone/api/pathing/calc/IPath.java +++ b/src/api/java/baritone/api/pathing/calc/IPath.java @@ -21,6 +21,8 @@ import baritone.api.Settings; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import java.util.List; @@ -51,7 +53,9 @@ public interface IPath { * This path is actually going to be executed in the world. Do whatever additional processing is required. * (as opposed to Path objects that are just constructed every frame for rendering) */ - default void postProcess() {} + default IPath postProcess() { + throw new UnsupportedOperationException(); + } /** * Returns the number of positions in this path. Equivalent to {@code positions().size()}. @@ -117,20 +121,48 @@ public interface IPath { * * @return The result of this cut-off operation */ - default IPath cutoffAtLoadedChunks() { - return this; + default IPath cutoffAtLoadedChunks(World world) { + throw new UnsupportedOperationException(); } /** * Cuts off this path using the min length and cutoff factor settings, and returns the resulting path. * Default implementation just returns this path, without the intended functionality. * + * @return The result of this cut-off operation * @see Settings#pathCutoffMinimumLength * @see Settings#pathCutoffFactor - * - * @return The result of this cut-off operation */ default IPath staticCutoff(Goal destination) { - return this; + throw new UnsupportedOperationException(); + } + + + /** + * Performs a series of checks to ensure that the assembly of the path went as expected. + */ + default void sanityCheck() { + List path = positions(); + List movements = movements(); + if (!getSrc().equals(path.get(0))) { + throw new IllegalStateException("Start node does not equal first path element"); + } + if (!getDest().equals(path.get(path.size() - 1))) { + throw new IllegalStateException("End node does not equal last path element"); + } + if (path.size() != movements.size() + 1) { + throw new IllegalStateException("Size of path array is unexpected"); + } + for (int i = 0; i < path.size() - 1; i++) { + BlockPos src = path.get(i); + BlockPos dest = path.get(i + 1); + IMovement movement = movements.get(i); + if (!src.equals(movement.getSrc())) { + throw new IllegalStateException("Path source is not equal to the movement source"); + } + if (!dest.equals(movement.getDest())) { + throw new IllegalStateException("Path destination is not equal to the movement destination"); + } + } } } diff --git a/src/api/java/baritone/api/pathing/calc/IPathFinder.java b/src/api/java/baritone/api/pathing/calc/IPathFinder.java index 446f7e05..f70196a6 100644 --- a/src/api/java/baritone/api/pathing/calc/IPathFinder.java +++ b/src/api/java/baritone/api/pathing/calc/IPathFinder.java @@ -18,6 +18,7 @@ package baritone.api.pathing.calc; import baritone.api.pathing.goals.Goal; +import baritone.api.utils.PathCalculationResult; import java.util.Optional; @@ -35,7 +36,7 @@ public interface IPathFinder { * * @return The final path */ - Optional calculate(long timeout); + PathCalculationResult calculate(long timeout); /** * Intended to be called concurrently with calculatePath from a different thread to tell if it's finished yet diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java index cb7a000e..bbbe1595 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -20,6 +20,7 @@ package baritone.api.pathing.goals; import net.minecraft.util.math.BlockPos; import java.util.Arrays; +import java.util.Optional; /** * Useful for automated combat (retreating specifically) @@ -32,16 +33,26 @@ public class GoalRunAway implements Goal { private final double distanceSq; + private final Optional maintainY; + public GoalRunAway(double distance, BlockPos... from) { + this(distance, Optional.empty(), from); + } + + public GoalRunAway(double distance, Optional maintainY, BlockPos... from) { if (from.length == 0) { throw new IllegalArgumentException(); } this.from = from; this.distanceSq = distance * distance; + this.maintainY = maintainY; } @Override public boolean isInGoal(int x, int y, int z) { + if (maintainY.isPresent() && maintainY.get() != y) { + return false; + } for (BlockPos p : from) { int diffX = x - p.getX(); int diffZ = z - p.getZ(); @@ -62,11 +73,19 @@ public class GoalRunAway implements Goal { min = h; } } - return -min; + min = -min; + if (maintainY.isPresent()) { + min = min * 0.5 + GoalYLevel.calculate(maintainY.get(), y); + } + return min; } @Override public String toString() { - return "GoalRunAwayFrom" + Arrays.asList(from); + if (maintainY.isPresent()) { + return "GoalRunAwayFromMaintainY y=" + maintainY.get() + ", " + Arrays.asList(from); + } else { + return "GoalRunAwayFrom" + Arrays.asList(from); + } } } diff --git a/src/api/java/baritone/api/process/IBaritoneProcess.java b/src/api/java/baritone/api/process/IBaritoneProcess.java new file mode 100644 index 00000000..db7588ab --- /dev/null +++ b/src/api/java/baritone/api/process/IBaritoneProcess.java @@ -0,0 +1,99 @@ +/* + * 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 . + */ + +package baritone.api.process; + +import baritone.api.IBaritone; +import baritone.api.behavior.IPathingBehavior; +import baritone.api.event.events.PathEvent; + +/** + * A process that can control the PathingBehavior. + *

+ * Differences between a baritone process and a behavior: + * Only one baritone process can be active at a time + * PathingBehavior can only be controlled by a process + *

+ * That's it actually + * + * @author leijurv + */ +public interface IBaritoneProcess { + + /** + * Would this process like to be in control? + * + * @return Whether or not this process would like to be in contorl. + */ + boolean isActive(); + + /** + * Called when this process is in control of pathing; Returns what Baritone should do. + * + * @param calcFailed {@code true} if this specific process was in control last tick, + * and there was a {@link PathEvent#CALC_FAILED} event last tick + * @param isSafeToCancel {@code true} if a {@link PathingCommandType#REQUEST_PAUSE} would happen this tick, and + * {@link IPathingBehavior} wouldn't actually tick. {@code false} if the PathExecutor reported + * pausing would be unsafe at the end of the last tick. Effectively "could request cancel or + * pause and have it happen right away" + * @return What the {@link IPathingBehavior} should do + */ + PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel); + + /** + * Returns whether or not this process should be treated as "temporary". + *

+ * If a process is temporary, it doesn't call {@link #onLostControl} on the processes that aren't execute because of it. + *

+ * For example, {@code CombatPauserProcess} and {@code PauseForAutoEatProcess} should return {@code true} always, + * and should return {@link #isActive} {@code true} only if there's something in range this tick, or if the player would like + * to start eating this tick. {@code PauseForAutoEatProcess} should only actually right click once onTick is called with + * {@code isSafeToCancel} true though. + * + * @return Whethor or not if this control is temporary + */ + boolean isTemporary(); + + /** + * Called if {@link #isActive} returned {@code true}, but another non-temporary + * process has control. Effectively the same as cancel. You want control but you + * don't get it. + */ + void onLostControl(); + + /** + * Used to determine which Process gains control if multiple are reporting {@link #isActive()}. The one + * that returns the highest value will be given control. + * + * @return A double representing the priority + */ + double priority(); + + /** + * Returns which bot this process is associated with. (5000000iq forward thinking) + * + * @return The Bot associated with this process + */ + IBaritone associatedWith(); + + /** + * Returns a user-friendly name for this process. Suitable for a HUD. + * + * @return A display name that's suitable for a HUD + */ + String displayName(); +} diff --git a/src/api/java/baritone/api/utils/interfaces/Toggleable.java b/src/api/java/baritone/api/process/ICustomGoalProcess.java similarity index 54% rename from src/api/java/baritone/api/utils/interfaces/Toggleable.java rename to src/api/java/baritone/api/process/ICustomGoalProcess.java index 359d6ee1..5084aff2 100644 --- a/src/api/java/baritone/api/utils/interfaces/Toggleable.java +++ b/src/api/java/baritone/api/process/ICustomGoalProcess.java @@ -15,40 +15,36 @@ * along with Baritone. If not, see . */ -package baritone.api.utils.interfaces; +package baritone.api.process; -/** - * @author Brady - * @since 8/20/2018 - */ -public interface Toggleable { +import baritone.api.pathing.goals.Goal; + +public interface ICustomGoalProcess extends IBaritoneProcess { /** - * Toggles the enabled state of this {@link Toggleable}. + * Sets the pathing goal * - * @return The new state. + * @param goal The new goal */ - boolean toggle(); + void setGoal(Goal goal); /** - * Sets the enabled state of this {@link Toggleable}. + * Starts path calculation and execution. + */ + void path(); + + /** + * @return The current goal + */ + Goal getGoal(); + + /** + * Sets the goal and begins the path execution. * - * @return The new state. + * @param goal The new goal */ - boolean setEnabled(boolean enabled); - - /** - * @return Whether or not this {@link Toggleable} object is enabled - */ - boolean isEnabled(); - - /** - * Called when the state changes from disabled to enabled - */ - default void onEnable() {} - - /** - * Called when the state changes from enabled to disabled - */ - default void onDisable() {} + default void setGoalAndPath(Goal goal) { + this.setGoal(goal); + this.path(); + } } diff --git a/src/api/java/baritone/api/behavior/IFollowBehavior.java b/src/api/java/baritone/api/process/IFollowProcess.java similarity index 62% rename from src/api/java/baritone/api/behavior/IFollowBehavior.java rename to src/api/java/baritone/api/process/IFollowProcess.java index c960fab3..ef869da4 100644 --- a/src/api/java/baritone/api/behavior/IFollowBehavior.java +++ b/src/api/java/baritone/api/process/IFollowProcess.java @@ -15,30 +15,37 @@ * along with Baritone. If not, see . */ -package baritone.api.behavior; +package baritone.api.process; import net.minecraft.entity.Entity; +import java.util.List; +import java.util.function.Predicate; + /** * @author Brady * @since 9/23/2018 */ -public interface IFollowBehavior extends IBehavior { +public interface IFollowProcess extends IBaritoneProcess { /** - * Set the follow target to the specified entity; + * Set the follow target to any entities matching this predicate * - * @param entity The entity to follow + * @param filter the predicate */ - void follow(Entity entity); + void follow(Predicate filter); /** - * @return The entity that is currently being followed + * @return The entities that are currently being followed. null if not currently following, empty if nothing matches the predicate */ - Entity following(); + List following(); + + Predicate currentFilter(); /** * Cancels the follow behavior, this will clear the current follow target. */ - void cancel(); + default void cancel() { + onLostControl(); + } } diff --git a/src/api/java/baritone/api/process/IGetToBlockProcess.java b/src/api/java/baritone/api/process/IGetToBlockProcess.java new file mode 100644 index 00000000..ff3dc9b5 --- /dev/null +++ b/src/api/java/baritone/api/process/IGetToBlockProcess.java @@ -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 . + */ + +package baritone.api.process; + +import net.minecraft.block.Block; + +/** + * but it rescans the world every once in a while so it doesn't get fooled by its cache + */ +public interface IGetToBlockProcess extends IBaritoneProcess { + + void getToBlock(Block block); +} diff --git a/src/api/java/baritone/api/behavior/IMineBehavior.java b/src/api/java/baritone/api/process/IMineProcess.java similarity index 81% rename from src/api/java/baritone/api/behavior/IMineBehavior.java rename to src/api/java/baritone/api/process/IMineProcess.java index 78ab6d6a..7ebabc9c 100644 --- a/src/api/java/baritone/api/behavior/IMineBehavior.java +++ b/src/api/java/baritone/api/process/IMineProcess.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.api.behavior; +package baritone.api.process; import net.minecraft.block.Block; @@ -23,7 +23,7 @@ import net.minecraft.block.Block; * @author Brady * @since 9/23/2018 */ -public interface IMineBehavior extends IBehavior { +public interface IMineProcess extends IBaritoneProcess { /** * Begin to search for and mine the specified blocks until @@ -31,9 +31,9 @@ public interface IMineBehavior extends IBehavior { * are mined. This is based on the first target block to mine. * * @param quantity The number of items to get from blocks mined - * @param blocks The blocks to mine + * @param blocks The blocks to mine */ - void mine(int quantity, String... blocks); + void mineByName(int quantity, String... blocks); /** * Begin to search for and mine the specified blocks until @@ -41,7 +41,7 @@ public interface IMineBehavior extends IBehavior { * are mined. This is based on the first target block to mine. * * @param quantity The number of items to get from blocks mined - * @param blocks The blocks to mine + * @param blocks The blocks to mine */ void mine(int quantity, Block... blocks); @@ -50,8 +50,8 @@ public interface IMineBehavior extends IBehavior { * * @param blocks The blocks to mine */ - default void mine(String... blocks) { - this.mine(0, blocks); + default void mineByName(String... blocks) { + mineByName(0, blocks); } /** @@ -60,11 +60,13 @@ public interface IMineBehavior extends IBehavior { * @param blocks The blocks to mine */ default void mine(Block... blocks) { - this.mine(0, blocks); + mine(0, blocks); } /** * Cancels the current mining task */ - void cancel(); + default void cancel() { + onLostControl(); + } } diff --git a/src/api/java/baritone/api/process/PathingCommand.java b/src/api/java/baritone/api/process/PathingCommand.java new file mode 100644 index 00000000..2caef158 --- /dev/null +++ b/src/api/java/baritone/api/process/PathingCommand.java @@ -0,0 +1,56 @@ +/* + * 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 . + */ + +package baritone.api.process; + +import baritone.api.pathing.goals.Goal; + +import java.util.Objects; + +/** + * @author leijurv + */ +public class PathingCommand { + + /** + * The target goal, may be {@code null}. + */ + public final Goal goal; + + /** + * The command type. + * + * @see PathingCommandType + */ + public final PathingCommandType commandType; + + /** + * Create a new {@link PathingCommand}. + * + * @param goal The target goal, may be {@code null}. + * @param commandType The command type, cannot be {@code null}. + * @throws NullPointerException if {@code commandType} is {@code null}. + * @see Goal + * @see PathingCommandType + */ + public PathingCommand(Goal goal, PathingCommandType commandType) { + Objects.requireNonNull(commandType); + + this.goal = goal; + this.commandType = commandType; + } +} diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java new file mode 100644 index 00000000..da64748a --- /dev/null +++ b/src/api/java/baritone/api/process/PathingCommandType.java @@ -0,0 +1,55 @@ +/* + * 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 . + */ + +package baritone.api.process; + +import baritone.api.Settings; + +public enum PathingCommandType { + + /** + * Set the goal and path. + *

+ * If you use this alongside a {@code null} goal, it will continue along its current path and current goal. + */ + SET_GOAL_AND_PATH, + + /** + * Has no effect on the current goal or path, just requests a pause + */ + REQUEST_PAUSE, + + /** + * Set the goal (regardless of {@code null}), and request a cancel of the current path (when safe) + */ + CANCEL_AND_SET_GOAL, + + /** + * Set the goal and path. + *

+ * If {@link Settings#cancelOnGoalInvalidation} is {@code true}, revalidate the + * current goal, and cancel if it's no longer valid, or if the new goal is {@code null}. + */ + REVALIDATE_GOAL_AND_PATH, + + /** + * Set the goal and path. + *

+ * Cancel the current path if the goals are not equal + */ + FORCE_REVALIDATE_GOAL_AND_PATH +} diff --git a/src/api/java/baritone/api/utils/PathCalculationResult.java b/src/api/java/baritone/api/utils/PathCalculationResult.java new file mode 100644 index 00000000..69d2a9b3 --- /dev/null +++ b/src/api/java/baritone/api/utils/PathCalculationResult.java @@ -0,0 +1,41 @@ +/* + * 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 . + */ + +package baritone.api.utils; + +import baritone.api.pathing.calc.IPath; + +import java.util.Optional; + +public class PathCalculationResult { + + public final Optional path; + public final Type type; + + public PathCalculationResult(Type type, Optional path) { + this.path = path; + this.type = type; + } + + public enum Type { + SUCCESS_TO_GOAL, + SUCCESS_SEGMENT, + FAILURE, + CANCELLATION, + EXCEPTION, + } +} diff --git a/src/api/java/baritone/api/utils/RayTraceUtils.java b/src/api/java/baritone/api/utils/RayTraceUtils.java index 1444c7e1..8b37ef9d 100644 --- a/src/api/java/baritone/api/utils/RayTraceUtils.java +++ b/src/api/java/baritone/api/utils/RayTraceUtils.java @@ -30,43 +30,11 @@ import java.util.Optional; * @since 8/25/2018 */ public final class RayTraceUtils { - /** - * The {@link Minecraft} instance - */ + private static final Minecraft mc = Minecraft.getMinecraft(); private RayTraceUtils() {} - /** - * Simulates a "vanilla" raytrace. A RayTraceResult returned by this method - * will be that of the next render pass given that the local player's yaw and - * pitch match the specified yaw and pitch values. This is particularly useful - * when you would like to simulate a "legit" raytrace with certainty that the only - * thing to achieve the desired outcome (whether it is hitting and entity or placing - * a block) can be done just by modifying user input. - * - * @param yaw The yaw to raytrace with - * @param pitch The pitch to raytrace with - * @return The calculated raytrace result - */ - public static RayTraceResult simulateRayTrace(float yaw, float pitch) { - RayTraceResult oldTrace = mc.objectMouseOver; - float oldYaw = mc.player.rotationYaw; - float oldPitch = mc.player.rotationPitch; - - mc.player.rotationYaw = yaw; - mc.player.rotationPitch = pitch; - - mc.entityRenderer.getMouseOver(1.0F); - RayTraceResult result = mc.objectMouseOver; - mc.objectMouseOver = oldTrace; - - mc.player.rotationYaw = oldYaw; - mc.player.rotationPitch = oldPitch; - - return result; - } - /** * Performs a block raytrace with the specified rotations. This should only be used when * any entity collisions can be ignored, because this method will not recognize if an @@ -75,9 +43,8 @@ public final class RayTraceUtils { * @param rotation The rotation to raytrace towards * @return The calculated raytrace result */ - public static RayTraceResult rayTraceTowards(Rotation rotation) { - double blockReachDistance = mc.playerController.getBlockReachDistance(); - Vec3d start = mc.player.getPositionEyes(1.0F); + public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance) { + Vec3d start = entity.getPositionEyes(1.0F); Vec3d direction = RotationUtils.calcVec3dFromRotation(rotation); Vec3d end = start.add( direction.x * blockReachDistance, diff --git a/src/api/java/baritone/api/utils/Rotation.java b/src/api/java/baritone/api/utils/Rotation.java index dc697169..ea10c7ec 100644 --- a/src/api/java/baritone/api/utils/Rotation.java +++ b/src/api/java/baritone/api/utils/Rotation.java @@ -86,7 +86,7 @@ public class Rotation { public Rotation clamp() { return new Rotation( this.yaw, - RotationUtils.clampPitch(this.pitch) + clampPitch(this.pitch) ); } @@ -95,7 +95,7 @@ public class Rotation { */ public Rotation normalize() { return new Rotation( - RotationUtils.normalizeYaw(this.yaw), + normalizeYaw(this.yaw), this.pitch ); } @@ -105,8 +105,35 @@ public class Rotation { */ public Rotation normalizeAndClamp() { return new Rotation( - RotationUtils.normalizeYaw(this.yaw), - RotationUtils.clampPitch(this.pitch) + normalizeYaw(this.yaw), + clampPitch(this.pitch) ); } + + /** + * Clamps the specified pitch value between -90 and 90. + * + * @param pitch The input pitch + * @return The clamped pitch + */ + public static float clampPitch(float pitch) { + return Math.max(-90, Math.min(90, pitch)); + } + + /** + * Normalizes the specified yaw value between -180 and 180. + * + * @param yaw The input yaw + * @return The normalized yaw + */ + public static float normalizeYaw(float yaw) { + float newYaw = yaw % 360F; + if (newYaw < -180F) { + newYaw += 360F; + } + if (newYaw >= 180F) { + newYaw -= 360F; + } + return newYaw; + } } diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java index a8449dc7..e1726812 100644 --- a/src/api/java/baritone/api/utils/RotationUtils.java +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -19,7 +19,6 @@ package baritone.api.utils; import net.minecraft.block.BlockFire; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.util.math.*; @@ -31,11 +30,6 @@ import java.util.Optional; */ public final class RotationUtils { - /** - * The {@link Minecraft} instance - */ - private static final Minecraft mc = Minecraft.getMinecraft(); - /** * Constant that a degree value is multiplied by to get the equivalent radian value */ @@ -60,33 +54,6 @@ public final class RotationUtils { private RotationUtils() {} - /** - * Clamps the specified pitch value between -90 and 90. - * - * @param pitch The input pitch - * @return The clamped pitch - */ - public static float clampPitch(float pitch) { - return Math.max(-90, Math.min(90, pitch)); - } - - /** - * Normalizes the specified yaw value between -180 and 180. - * - * @param yaw The input yaw - * @return The normalized yaw - */ - public static float normalizeYaw(float yaw) { - float newYaw = yaw % 360F; - if (newYaw < -180F) { - newYaw += 360F; - } - if (newYaw >= 180F) { - newYaw -= 360F; - } - return newYaw; - } - /** * Calculates the rotation from BlockPosdest to BlockPosorig * @@ -168,7 +135,7 @@ public final class RotationUtils { * @param pos The target block position * @return The optional rotation */ - public static Optional reachable(Entity entity, BlockPos pos) { + public static Optional reachable(Entity entity, BlockPos pos, double blockReachDistance) { if (pos.equals(RayTraceUtils.getSelectedBlock().orElse(null))) { /* * why add 0.0001? @@ -182,19 +149,19 @@ public final class RotationUtils { */ return Optional.of(new Rotation(entity.rotationYaw, entity.rotationPitch + 0.0001F)); } - Optional possibleRotation = reachableCenter(entity, pos); + Optional possibleRotation = reachableCenter(entity, pos, blockReachDistance); //System.out.println("center: " + possibleRotation); if (possibleRotation.isPresent()) { return possibleRotation; } - IBlockState state = mc.world.getBlockState(pos); + IBlockState state = entity.world.getBlockState(pos); AxisAlignedBB aabb = state.getBoundingBox(entity.world, pos); for (Vec3d sideOffset : BLOCK_SIDE_MULTIPLIERS) { double xDiff = aabb.minX * sideOffset.x + aabb.maxX * (1 - sideOffset.x); double yDiff = aabb.minY * sideOffset.y + aabb.maxY * (1 - sideOffset.y); double zDiff = aabb.minZ * sideOffset.z + aabb.maxZ * (1 - sideOffset.z); - possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff)); + possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff), blockReachDistance); if (possibleRotation.isPresent()) { return possibleRotation; } @@ -212,9 +179,9 @@ public final class RotationUtils { * @param offsetPos The position of the block with the offset applied. * @return The optional rotation */ - public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos) { + public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) { Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos); - RayTraceResult result = RayTraceUtils.rayTraceTowards(rotation); + RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance); //System.out.println(result); if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) { if (result.getBlockPos().equals(pos)) { @@ -235,7 +202,7 @@ public final class RotationUtils { * @param pos The target block position * @return The optional rotation */ - public static Optional reachableCenter(Entity entity, BlockPos pos) { - return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(pos)); + public static Optional reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) { + return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(pos), blockReachDistance); } } diff --git a/src/launch/java/baritone/launch/mixins/MixinAnvilChunkLoader.java b/src/launch/java/baritone/launch/mixins/MixinAnvilChunkLoader.java index 4ffb5abc..8b3ea0af 100644 --- a/src/launch/java/baritone/launch/mixins/MixinAnvilChunkLoader.java +++ b/src/launch/java/baritone/launch/mixins/MixinAnvilChunkLoader.java @@ -32,7 +32,9 @@ import java.io.File; @Mixin(AnvilChunkLoader.class) public class MixinAnvilChunkLoader implements IAnvilChunkLoader { - @Shadow @Final private File chunkSaveLocation; + @Shadow + @Final + private File chunkSaveLocation; @Override public File getChunkSaveLocation() { diff --git a/src/launch/java/baritone/launch/mixins/MixinBlockPos.java b/src/launch/java/baritone/launch/mixins/MixinBlockPos.java index 013980a9..b0aa75ba 100644 --- a/src/launch/java/baritone/launch/mixins/MixinBlockPos.java +++ b/src/launch/java/baritone/launch/mixins/MixinBlockPos.java @@ -35,6 +35,12 @@ public class MixinBlockPos extends Vec3i { super(xIn, yIn, zIn); } + /** + * The purpose of this was to ensure a friendly name for when we print raw + * block positions to chat in the context of an obfuscated environment. + * + * @return a string representation of the object. + */ @Override @Nonnull public String toString() { diff --git a/src/launch/java/baritone/launch/mixins/MixinChunkProviderServer.java b/src/launch/java/baritone/launch/mixins/MixinChunkProviderServer.java index 246c368e..6d5a5421 100644 --- a/src/launch/java/baritone/launch/mixins/MixinChunkProviderServer.java +++ b/src/launch/java/baritone/launch/mixins/MixinChunkProviderServer.java @@ -31,7 +31,9 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(ChunkProviderServer.class) public class MixinChunkProviderServer implements IChunkProviderServer { - @Shadow @Final private IChunkLoader chunkLoader; + @Shadow + @Final + private IChunkLoader chunkLoader; @Override public IChunkLoader getChunkLoader() { diff --git a/src/launch/java/baritone/launch/mixins/MixinEntity.java b/src/launch/java/baritone/launch/mixins/MixinEntity.java index fe019bb7..8ca1743f 100644 --- a/src/launch/java/baritone/launch/mixins/MixinEntity.java +++ b/src/launch/java/baritone/launch/mixins/MixinEntity.java @@ -19,14 +19,17 @@ package baritone.launch.mixins; import baritone.Baritone; import baritone.api.event.events.RotationMoveEvent; -import baritone.api.event.events.type.EventState; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static org.spongepowered.asm.lib.Opcodes.GETFIELD; + /** * @author Brady * @since 8/21/2018 @@ -34,23 +37,38 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Entity.class) public class MixinEntity { + @Shadow + public float rotationYaw; + + /** + * Event called to override the movement direction when walking + */ + private RotationMoveEvent motionUpdateRotationEvent; + @Inject( method = "moveRelative", at = @At("HEAD") ) private void preMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) { - Entity _this = (Entity) (Object) this; - if (EntityPlayerSP.class.isInstance(_this)) - Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.PRE, RotationMoveEvent.Type.MOTION_UPDATE)); + // noinspection ConstantConditions + if (EntityPlayerSP.class.isInstance(this)) { + this.motionUpdateRotationEvent = new RotationMoveEvent((EntityPlayerSP) (Object) this, RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw); + Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(this.motionUpdateRotationEvent); + } } - @Inject( + @Redirect( method = "moveRelative", - at = @At("RETURN") + at = @At( + value = "FIELD", + opcode = GETFIELD, + target = "net/minecraft/entity/Entity.rotationYaw:F" + ) ) - private void postMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) { - Entity _this = (Entity) (Object) this; - if (EntityPlayerSP.class.isInstance(_this)) - Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.POST, RotationMoveEvent.Type.MOTION_UPDATE)); + private float overrideYaw(Entity self) { + if (self instanceof EntityPlayerSP) { + return this.motionUpdateRotationEvent.getYaw(); + } + return self.rotationYaw; } } diff --git a/src/launch/java/baritone/launch/mixins/MixinEntityLivingBase.java b/src/launch/java/baritone/launch/mixins/MixinEntityLivingBase.java index 6313b3a1..8e2eb515 100644 --- a/src/launch/java/baritone/launch/mixins/MixinEntityLivingBase.java +++ b/src/launch/java/baritone/launch/mixins/MixinEntityLivingBase.java @@ -19,41 +19,59 @@ package baritone.launch.mixins; import baritone.Baritone; import baritone.api.event.events.RotationMoveEvent; -import baritone.api.event.events.type.EventState; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.world.World; 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.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static org.spongepowered.asm.lib.Opcodes.GETFIELD; + /** * @author Brady * @since 9/10/2018 */ @Mixin(EntityLivingBase.class) -public class MixinEntityLivingBase { +public abstract class MixinEntityLivingBase extends Entity { + + /** + * Event called to override the movement direction when jumping + */ + private RotationMoveEvent jumpRotationEvent; + + public MixinEntityLivingBase(World worldIn, RotationMoveEvent jumpRotationEvent) { + super(worldIn); + this.jumpRotationEvent = jumpRotationEvent; + } @Inject( method = "jump", at = @At("HEAD") ) - private void preJump(CallbackInfo ci) { - EntityLivingBase _this = (EntityLivingBase) (Object) this; - // This uses Class.isInstance instead of instanceof since proguard optimizes out the instanceof (since MixinEntityLivingBase could never be instanceof EntityLivingBase in normal java) - // but proguard isn't smart enough to optimize out this Class.isInstance =) - if (EntityPlayerSP.class.isInstance(_this)) - Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.PRE, RotationMoveEvent.Type.JUMP)); + private void preMoveRelative(CallbackInfo ci) { + // noinspection ConstantConditions + if (EntityPlayerSP.class.isInstance(this)) { + this.jumpRotationEvent = new RotationMoveEvent((EntityPlayerSP) (Object) this, RotationMoveEvent.Type.JUMP, this.rotationYaw); + Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent); + } } - @Inject( + @Redirect( method = "jump", - at = @At("RETURN") + at = @At( + value = "FIELD", + opcode = GETFIELD, + target = "net/minecraft/entity/EntityLivingBase.rotationYaw:F" + ) ) - private void postJump(CallbackInfo ci) { - EntityLivingBase _this = (EntityLivingBase) (Object) this; - // See above - if (EntityPlayerSP.class.isInstance(_this)) - Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.POST, RotationMoveEvent.Type.JUMP)); + private float overrideYaw(EntityLivingBase self) { + if (self instanceof EntityPlayerSP) { + return this.jumpRotationEvent.getYaw(); + } + return self.rotationYaw; } } diff --git a/src/launch/java/baritone/launch/mixins/MixinEntityPlayerSP.java b/src/launch/java/baritone/launch/mixins/MixinEntityPlayerSP.java index dd121ead..a180df5c 100644 --- a/src/launch/java/baritone/launch/mixins/MixinEntityPlayerSP.java +++ b/src/launch/java/baritone/launch/mixins/MixinEntityPlayerSP.java @@ -85,6 +85,6 @@ public class MixinEntityPlayerSP { ) private boolean isAllowFlying(PlayerCapabilities capabilities) { PathingBehavior pathingBehavior = Baritone.INSTANCE.getPathingBehavior(); - return (!pathingBehavior.isEnabled() || !pathingBehavior.isPathing()) && capabilities.allowFlying; + return !pathingBehavior.isPathing() && capabilities.allowFlying; } } diff --git a/src/launch/java/baritone/launch/mixins/MixinEntityRenderer.java b/src/launch/java/baritone/launch/mixins/MixinEntityRenderer.java index 0fc1b246..174b9e3c 100644 --- a/src/launch/java/baritone/launch/mixins/MixinEntityRenderer.java +++ b/src/launch/java/baritone/launch/mixins/MixinEntityRenderer.java @@ -33,7 +33,7 @@ public class MixinEntityRenderer { at = @At( value = "INVOKE_STRING", target = "Lnet/minecraft/profiler/Profiler;endStartSection(Ljava/lang/String;)V", - args = { "ldc=hand" } + args = {"ldc=hand"} ) ) private void renderWorldPass(int pass, float partialTicks, long finishTimeNano, CallbackInfo ci) { diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java index 30d4109b..3826f0d7 100644 --- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java +++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java @@ -83,10 +83,9 @@ public class MixinMinecraft { ) ) private void runTick(CallbackInfo ci) { - Minecraft mc = (Minecraft) (Object) this; Baritone.INSTANCE.getGameEventHandler().onTick(new TickEvent( EventState.PRE, - (mc.player != null && mc.world != null) + (player != null && world != null) ? TickEvent.Type.IN : TickEvent.Type.OUT )); @@ -142,7 +141,7 @@ public class MixinMinecraft { ) ) private boolean isAllowUserInput(GuiScreen screen) { - return (Baritone.INSTANCE.getPathingBehavior().getCurrent() != null && Baritone.INSTANCE.getPathingBehavior().isEnabled() && player != null) || screen.allowUserInput; + return (Baritone.INSTANCE.getPathingBehavior().getCurrent() != null && player != null) || screen.allowUserInput; } @Inject( diff --git a/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java b/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java index 3f5f297b..bf15bfc3 100644 --- a/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java +++ b/src/launch/java/baritone/launch/mixins/MixinNetworkManager.java @@ -77,7 +77,8 @@ public class MixinNetworkManager { ) private void preProcessPacket(ChannelHandlerContext context, Packet packet, CallbackInfo ci) { if (this.direction == EnumPacketDirection.CLIENTBOUND) { - Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent((NetworkManager) (Object) this, EventState.PRE, packet));} + Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent((NetworkManager) (Object) this, EventState.PRE, packet)); + } } @Inject( diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index a0d5ba84..f4546012 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -18,16 +18,24 @@ package baritone; import baritone.api.BaritoneAPI; -import baritone.api.IBaritoneProvider; +import baritone.api.IBaritone; import baritone.api.Settings; import baritone.api.event.listener.IGameEventListener; -import baritone.behavior.*; +import baritone.behavior.Behavior; +import baritone.behavior.LookBehavior; +import baritone.behavior.MemoryBehavior; +import baritone.behavior.PathingBehavior; import baritone.cache.WorldProvider; import baritone.cache.WorldScanner; import baritone.event.GameEventHandler; +import baritone.process.CustomGoalProcess; +import baritone.process.FollowProcess; +import baritone.process.GetToBlockProcess; +import baritone.process.MineProcess; import baritone.utils.BaritoneAutoTest; import baritone.utils.ExampleBaritoneControl; import baritone.utils.InputOverrideHandler; +import baritone.utils.PathingControlManager; import net.minecraft.client.Minecraft; import java.io.File; @@ -44,50 +52,57 @@ import java.util.concurrent.TimeUnit; * @author Brady * @since 7/31/2018 10:50 PM */ -public enum Baritone implements IBaritoneProvider { +public enum Baritone implements IBaritone { /** * Singleton instance of this class */ INSTANCE; + private static ThreadPoolExecutor threadPool; + private static File dir; + + static { + threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); + + dir = new File(Minecraft.getMinecraft().gameDir, "baritone"); + if (!Files.exists(dir.toPath())) { + try { + Files.createDirectories(dir.toPath()); + } catch (IOException ignored) {} + } + } + /** * Whether or not {@link Baritone#init()} has been called yet */ private boolean initialized; private GameEventHandler gameEventHandler; - private InputOverrideHandler inputOverrideHandler; - private Settings settings; - private File dir; - private ThreadPoolExecutor threadPool; private List behaviors; private PathingBehavior pathingBehavior; private LookBehavior lookBehavior; private MemoryBehavior memoryBehavior; - private FollowBehavior followBehavior; - private MineBehavior mineBehavior; + private InputOverrideHandler inputOverrideHandler; - /** - * Whether or not Baritone is active - */ - private boolean active; + private FollowProcess followProcess; + private MineProcess mineProcess; + private GetToBlockProcess getToBlockProcess; + private CustomGoalProcess customGoalProcess; + + private PathingControlManager pathingControlManager; + + private WorldProvider worldProvider; Baritone() { - this.gameEventHandler = new GameEventHandler(); + this.gameEventHandler = new GameEventHandler(this); } public synchronized void init() { if (initialized) { return; } - this.threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); - this.inputOverrideHandler = new InputOverrideHandler(); - - // Acquire the "singleton" instance of the settings directly from the API - // We might want to change this... - this.settings = BaritoneAPI.getSettings(); this.behaviors = new ArrayList<>(); { @@ -95,26 +110,29 @@ public enum Baritone implements IBaritoneProvider { pathingBehavior = new PathingBehavior(this); lookBehavior = new LookBehavior(this); memoryBehavior = new MemoryBehavior(this); - followBehavior = new FollowBehavior(this); - mineBehavior = new MineBehavior(this); + inputOverrideHandler = new InputOverrideHandler(this); new ExampleBaritoneControl(this); } + + this.pathingControlManager = new PathingControlManager(this); + { + followProcess = new FollowProcess(this); + mineProcess = new MineProcess(this); + customGoalProcess = new CustomGoalProcess(this); // very high iq + getToBlockProcess = new GetToBlockProcess(this); + } + + this.worldProvider = new WorldProvider(); + if (BaritoneAutoTest.ENABLE_AUTO_TEST) { registerEventListener(BaritoneAutoTest.INSTANCE); } - this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone"); - if (!Files.exists(dir.toPath())) { - try { - Files.createDirectories(dir.toPath()); - } catch (IOException ignored) {} - } - this.active = true; this.initialized = true; } - public boolean isInitialized() { - return this.initialized; + public PathingControlManager getPathingControlManager() { + return pathingControlManager; } public IGameEventListener getGameEventHandler() { @@ -129,18 +147,24 @@ public enum Baritone implements IBaritoneProvider { return this.behaviors; } - public Executor getExecutor() { - return threadPool; - } - public void registerBehavior(Behavior behavior) { this.behaviors.add(behavior); this.registerEventListener(behavior); } @Override - public FollowBehavior getFollowBehavior() { - return followBehavior; + public CustomGoalProcess getCustomGoalProcess() { // Iffy + return customGoalProcess; + } + + @Override + public GetToBlockProcess getGetToBlockProcess() { // Iffy + return getToBlockProcess; + } + + @Override + public FollowProcess getFollowProcess() { + return followProcess; } @Override @@ -154,8 +178,8 @@ public enum Baritone implements IBaritoneProvider { } @Override - public MineBehavior getMineBehavior() { - return mineBehavior; + public MineProcess getMineProcess() { + return mineProcess; } @Override @@ -165,7 +189,7 @@ public enum Baritone implements IBaritoneProvider { @Override public WorldProvider getWorldProvider() { - return WorldProvider.INSTANCE; + return worldProvider; } @Override @@ -178,19 +202,15 @@ public enum Baritone implements IBaritoneProvider { this.gameEventHandler.registerEventListener(listener); } - public boolean isActive() { - return this.active; - } - - public Settings getSettings() { - return this.settings; - } - public static Settings settings() { - return Baritone.INSTANCE.settings; // yolo + return BaritoneAPI.getSettings(); } - public File getDir() { - return this.dir; + public static File getDir() { + return dir; + } + + public static Executor getExecutor() { + return threadPool; } } diff --git a/src/main/java/baritone/BaritoneProvider.java b/src/main/java/baritone/BaritoneProvider.java index 2e9b3b30..a80dfe5e 100644 --- a/src/main/java/baritone/BaritoneProvider.java +++ b/src/main/java/baritone/BaritoneProvider.java @@ -17,59 +17,17 @@ package baritone; +import baritone.api.IBaritone; import baritone.api.IBaritoneProvider; -import baritone.api.behavior.*; -import baritone.api.cache.IWorldProvider; -import baritone.api.cache.IWorldScanner; -import baritone.api.event.listener.IGameEventListener; -import baritone.cache.WorldProvider; -import baritone.cache.WorldScanner; +import net.minecraft.client.entity.EntityPlayerSP; /** - * todo fix this cancer - * * @author Brady * @since 9/29/2018 */ public final class BaritoneProvider implements IBaritoneProvider { - @Override - public IFollowBehavior getFollowBehavior() { - return Baritone.INSTANCE.getFollowBehavior(); - } - - @Override - public ILookBehavior getLookBehavior() { - return Baritone.INSTANCE.getLookBehavior(); - } - - @Override - public IMemoryBehavior getMemoryBehavior() { - return Baritone.INSTANCE.getMemoryBehavior(); - } - - @Override - public IMineBehavior getMineBehavior() { - return Baritone.INSTANCE.getMineBehavior(); - } - - @Override - public IPathingBehavior getPathingBehavior() { - return Baritone.INSTANCE.getPathingBehavior(); - } - - @Override - public IWorldProvider getWorldProvider() { - return WorldProvider.INSTANCE; - } - - @Override - public IWorldScanner getWorldScanner() { - return WorldScanner.INSTANCE; - } - - @Override - public void registerEventListener(IGameEventListener listener) { - Baritone.INSTANCE.registerEventListener(listener); + public IBaritone getBaritoneForPlayer(EntityPlayerSP player) { + return Baritone.INSTANCE; // pwnage } } diff --git a/src/main/java/baritone/behavior/Behavior.java b/src/main/java/baritone/behavior/Behavior.java index 713e98f0..66434d7a 100644 --- a/src/main/java/baritone/behavior/Behavior.java +++ b/src/main/java/baritone/behavior/Behavior.java @@ -21,7 +21,7 @@ import baritone.Baritone; import baritone.api.behavior.IBehavior; /** - * A type of game event listener that can be toggled. + * A type of game event listener that is given {@link Baritone} instance context. * * @author Brady * @since 8/1/2018 6:29 PM @@ -30,49 +30,8 @@ public class Behavior implements IBehavior { public final Baritone baritone; - /** - * Whether or not this behavior is enabled - */ - private boolean enabled = true; - protected Behavior(Baritone baritone) { this.baritone = baritone; baritone.registerBehavior(this); } - - /** - * Toggles the enabled state of this {@link Behavior}. - * - * @return The new state. - */ - @Override - public final boolean toggle() { - return this.setEnabled(!this.isEnabled()); - } - - /** - * Sets the enabled state of this {@link Behavior}. - * - * @return The new state. - */ - @Override - public final boolean setEnabled(boolean enabled) { - if (enabled == this.enabled) { - return this.enabled; - } - if (this.enabled = enabled) { - this.onEnable(); - } else { - this.onDisable(); - } - return this.enabled; - } - - /** - * @return Whether or not this {@link Behavior} is active. - */ - @Override - public final boolean isEnabled() { - return this.enabled; - } } diff --git a/src/main/java/baritone/behavior/FollowBehavior.java b/src/main/java/baritone/behavior/FollowBehavior.java deleted file mode 100644 index 00fbe1c5..00000000 --- a/src/main/java/baritone/behavior/FollowBehavior.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 . - */ - -package baritone.behavior; - -import baritone.Baritone; -import baritone.api.behavior.IFollowBehavior; -import baritone.api.event.events.TickEvent; -import baritone.api.pathing.goals.GoalNear; -import baritone.api.pathing.goals.GoalXZ; -import baritone.utils.Helper; -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; - -/** - * Follow an entity - * - * @author leijurv - */ -public final class FollowBehavior extends Behavior implements IFollowBehavior, Helper { - - private Entity following; - - public FollowBehavior(Baritone baritone) { - super(baritone); - } - - @Override - public void onTick(TickEvent event) { - if (event.getType() == TickEvent.Type.OUT) { - following = null; - return; - } - if (following == null) { - return; - } - // lol this is trashy but it works - BlockPos pos; - if (Baritone.settings().followOffsetDistance.get() == 0) { - pos = following.getPosition(); - } else { - GoalXZ g = GoalXZ.fromDirection(following.getPositionVector(), Baritone.settings().followOffsetDirection.get(), Baritone.settings().followOffsetDistance.get()); - pos = new BlockPos(g.getX(), following.posY, g.getZ()); - } - baritone.getPathingBehavior().setGoal(new GoalNear(pos, Baritone.settings().followRadius.get())); - ((PathingBehavior) baritone.getPathingBehavior()).revalidateGoal(); - baritone.getPathingBehavior().path(); - } - - @Override - public void follow(Entity entity) { - this.following = entity; - } - - @Override - public Entity following() { - return this.following; - } - - @Override - public void cancel() { - baritone.getPathingBehavior().cancel(); - follow(null); - } -} diff --git a/src/main/java/baritone/behavior/LookBehavior.java b/src/main/java/baritone/behavior/LookBehavior.java index ac3a4698..ee8548a2 100644 --- a/src/main/java/baritone/behavior/LookBehavior.java +++ b/src/main/java/baritone/behavior/LookBehavior.java @@ -26,6 +26,7 @@ import baritone.api.utils.Rotation; import baritone.utils.Helper; public final class LookBehavior extends Behavior implements ILookBehavior, Helper { + /** * Target's values are as follows: *

@@ -63,7 +64,7 @@ public final class LookBehavior extends Behavior implements ILookBehavior, Helpe } // Whether or not we're going to silently set our angles - boolean silent = Baritone.settings().antiCheatCompatibility.get(); + boolean silent = Baritone.settings().antiCheatCompatibility.get() && !this.force; switch (event.getState()) { case PRE: { @@ -76,14 +77,15 @@ public final class LookBehavior extends Behavior implements ILookBehavior, Helpe nudgeToLevel(); } this.target = null; - } else if (silent) { + } + if (silent) { this.lastYaw = player().rotationYaw; player().rotationYaw = this.target.getYaw(); } break; } case POST: { - if (!this.force && silent) { + if (silent) { player().rotationYaw = this.lastYaw; this.target = null; } @@ -97,26 +99,20 @@ public final class LookBehavior extends Behavior implements ILookBehavior, Helpe @Override public void onPlayerRotationMove(RotationMoveEvent event) { if (this.target != null && !this.force) { - switch (event.getState()) { - case PRE: - this.lastYaw = player().rotationYaw; - player().rotationYaw = this.target.getYaw(); - break; - case POST: - player().rotationYaw = this.lastYaw; - // If we have antiCheatCompatibility on, we're going to use the target value later in onPlayerUpdate() - // Also the type has to be MOTION_UPDATE because that is called after JUMP - if (!Baritone.settings().antiCheatCompatibility.get() && event.getType() == RotationMoveEvent.Type.MOTION_UPDATE) { - this.target = null; - } - break; - default: - break; + event.setYaw(this.target.getYaw()); + + // If we have antiCheatCompatibility on, we're going to use the target value later in onPlayerUpdate() + // Also the type has to be MOTION_UPDATE because that is called after JUMP + if (!Baritone.settings().antiCheatCompatibility.get() && event.getType() == RotationMoveEvent.Type.MOTION_UPDATE) { + this.target = null; } } } + /** + * Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1}) + */ private void nudgeToLevel() { if (player().rotationPitch < -20) { player().rotationPitch++; diff --git a/src/main/java/baritone/behavior/MemoryBehavior.java b/src/main/java/baritone/behavior/MemoryBehavior.java index 510cecff..1e8e069a 100644 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ b/src/main/java/baritone/behavior/MemoryBehavior.java @@ -26,7 +26,6 @@ import baritone.api.event.events.PacketEvent; import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.type.EventState; import baritone.cache.Waypoint; -import baritone.cache.WorldProvider; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import net.minecraft.block.BlockBed; @@ -122,13 +121,13 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H @Override public void onBlockInteract(BlockInteractEvent event) { if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(event.getPos()) instanceof BlockBed) { - WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos())); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos())); } } @Override public void onPlayerDeath() { - WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet())); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet())); } private Optional getInventoryFromWindow(int windowId) { @@ -143,7 +142,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H } private WorldDataContainer getCurrentContainer() { - return this.worldDataContainers.computeIfAbsent(WorldProvider.INSTANCE.getCurrentWorld(), data -> new WorldDataContainer()); + return this.worldDataContainers.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), data -> new WorldDataContainer()); } @Override diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index d8bf9a1d..b1d2fc56 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -28,12 +28,13 @@ import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalXZ; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.PathCalculationResult; import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.pathing.calc.AStarPathFinder; import baritone.pathing.calc.AbstractNodeCostSearch; -import baritone.pathing.calc.CutoffPath; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; +import baritone.pathing.path.CutoffPath; import baritone.pathing.path.PathExecutor; import baritone.utils.BlockBreakHelper; import baritone.utils.Helper; @@ -52,6 +53,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, private Goal goal; + private boolean safeToCancel; + private boolean pauseRequestedLastTick; + private boolean cancelRequested; + private boolean calcFailedLastTick; + private volatile boolean isPathCalcInProgress; private final Object pathCalcLock = new Object(); @@ -72,8 +78,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, private void dispatchEvents() { ArrayList curr = new ArrayList<>(); toDispatch.drainTo(curr); + calcFailedLastTick = curr.contains(PathEvent.CALC_FAILED); for (PathEvent event : curr) { - Baritone.INSTANCE.getGameEventHandler().onPathEvent(event); + baritone.getGameEventHandler().onPathEvent(event); } } @@ -81,18 +88,30 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, public void onTick(TickEvent event) { dispatchEvents(); if (event.getType() == TickEvent.Type.OUT) { - cancel(); + secretInternalSegmentCancel(); + baritone.getPathingControlManager().cancelEverything(); return; } + baritone.getPathingControlManager().preTick(); tickPath(); dispatchEvents(); } private void tickPath() { + if (pauseRequestedLastTick && safeToCancel) { + pauseRequestedLastTick = false; + baritone.getInputOverrideHandler().clearAllKeys(); + BlockBreakHelper.stopBreakingBlock(); + return; + } + if (cancelRequested) { + cancelRequested = false; + baritone.getInputOverrideHandler().clearAllKeys(); + } if (current == null) { return; } - boolean safe = current.onTick(); + safeToCancel = current.onTick(); synchronized (pathPlanLock) { if (current.failed() || current.finished()) { current = null; @@ -134,7 +153,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return; } // at this point, we know current is in progress - if (safe && next != null && next.snipsnapifpossible()) { + if (safeToCancel && next != null && next.snipsnapifpossible()) { // a movement just ended; jump directly onto the next path logDebug("Splicing into planned next path early..."); queuePathEvent(PathEvent.SPLICING_ONTO_NEXT_EARLY); @@ -143,6 +162,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, current.onTick(); return; } + current = current.trySplice(next); + if (next != null && current.getPath().getDest().equals(next.getPath().getDest())) { + next = null; + } synchronized (pathCalcLock) { if (isPathCalcInProgress) { // if we aren't calculating right now @@ -191,14 +214,13 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition())); } - @Override - public void setGoal(Goal goal) { + public void secretInternalSetGoal(Goal goal) { this.goal = goal; } - public boolean setGoalAndPath(Goal goal) { - setGoal(goal); - return path(); + public boolean secretInternalSetGoalAndPath(Goal goal) { + secretInternalSetGoal(goal); + return secretInternalPath(); } @Override @@ -226,17 +248,60 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return this.current != null; } + public boolean isSafeToCancel() { + return current == null || safeToCancel; + } + + public void requestPause() { + pauseRequestedLastTick = true; + } + + public boolean cancelSegmentIfSafe() { + if (isSafeToCancel()) { + secretInternalSegmentCancel(); + return true; + } + return false; + } + @Override - public void cancel() { + public boolean cancelEverything() { + boolean doIt = isSafeToCancel(); + if (doIt) { + secretInternalSegmentCancel(); + } + baritone.getPathingControlManager().cancelEverything(); + return doIt; + } + + public boolean calcFailedLastTick() { // NOT exposed on public api + return calcFailedLastTick; + } + + public void softCancelIfSafe() { + if (!isSafeToCancel()) { + return; + } + current = null; + next = null; + cancelRequested = true; + AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel); + // do everything BUT clear keys + } + + // just cancel the current path + public void secretInternalSegmentCancel() { queuePathEvent(PathEvent.CANCELED); current = null; next = null; - Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); + baritone.getInputOverrideHandler().clearAllKeys(); AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel); BlockBreakHelper.stopBreakingBlock(); } public void forceCancel() { // NOT exposed on public api + cancelEverything(); + secretInternalSegmentCancel(); isPathCalcInProgress = false; } @@ -245,8 +310,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, * * @return true if this call started path calculation, false if it was already calculating or executing a path */ - @Override - public boolean path() { + public boolean secretInternalPath() { if (goal == null) { return false; } @@ -327,15 +391,16 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, isPathCalcInProgress = true; } CalculationContext context = new CalculationContext(); // not safe to create on the other thread, it looks up a lot of stuff in minecraft - Baritone.INSTANCE.getExecutor().execute(() -> { + Baritone.getExecutor().execute(() -> { if (talkAboutIt) { logDebug("Starting to search for path from " + start + " to " + goal); } - Optional path = findPath(start, previous, context); + PathCalculationResult calcResult = findPath(start, previous, context); + Optional path = calcResult.path; if (Baritone.settings().cutoffAtLoadBoundary.get()) { path = path.map(p -> { - IPath result = p.cutoffAtLoadedChunks(); + IPath result = p.cutoffAtLoadedChunks(context.world()); if (result instanceof CutoffPath) { logDebug("Cutting off path at edge of loaded chunks"); @@ -364,7 +429,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING); current = executor.get(); } else { - queuePathEvent(PathEvent.CALC_FAILED); + if (calcResult.type != PathCalculationResult.Type.CANCELLATION && calcResult.type != PathCalculationResult.Type.EXCEPTION) { + // don't dispatch CALC_FAILED on cancellation + queuePathEvent(PathEvent.CALC_FAILED); + } } } else { if (next == null) { @@ -378,18 +446,16 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, throw new IllegalStateException("I have no idea what to do with this path"); } } - } - - if (talkAboutIt && current != null && current.getPath() != null) { - if (goal == null || goal.isInGoal(current.getPath().getDest())) { - logDebug("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); - } else { - logDebug("Found path segment from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); - + if (talkAboutIt && current != null && current.getPath() != null) { + if (goal == null || goal.isInGoal(current.getPath().getDest())) { + logDebug("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); + } else { + logDebug("Found path segment from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); + } + } + synchronized (pathCalcLock) { + isPathCalcInProgress = false; } - } - synchronized (pathCalcLock) { - isPathCalcInProgress = false; } }); } @@ -400,19 +466,15 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, * @param start * @return */ - private Optional findPath(BlockPos start, Optional previous, CalculationContext context) { + private PathCalculationResult findPath(BlockPos start, Optional previous, CalculationContext context) { Goal goal = this.goal; if (goal == null) { logDebug("no goal"); - return Optional.empty(); + return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, Optional.empty()); } - if (Baritone.settings().simplifyUnloadedYCoord.get()) { - BlockPos pos = null; - if (goal instanceof IGoalRenderPos) { - pos = ((IGoalRenderPos) goal).getGoalPos(); - } - - if (pos != null && world().getChunk(pos) instanceof EmptyChunk) { + if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) { + BlockPos pos = ((IGoalRenderPos) goal).getGoalPos(); + if (context.world().getChunk(pos) instanceof EmptyChunk) { logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance"); goal = new GoalXZ(pos.getX(), pos.getZ()); } @@ -435,25 +497,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } catch (Exception e) { logDebug("Pathing exception: " + e); e.printStackTrace(); - return Optional.empty(); - } - } - - public void revalidateGoal() { - if (!Baritone.settings().cancelOnGoalInvalidation.get()) { - return; - } - synchronized (pathPlanLock) { - if (current == null || goal == null) { - return; - } - Goal intended = current.getPath().getGoal(); - BlockPos end = current.getPath().getDest(); - if (intended.isInGoal(end) && !goal.isInGoal(end)) { - // this path used to end in the goal - // but the goal has changed, so there's no reason to continue... - cancel(); - } + return new PathCalculationResult(PathCalculationResult.Type.EXCEPTION, Optional.empty()); } } @@ -461,9 +505,4 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, public void onRenderPass(RenderEvent event) { PathRenderer.render(event, this); } - - @Override - public void onDisable() { - Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); - } } diff --git a/src/main/java/baritone/cache/CachedChunk.java b/src/main/java/baritone/cache/CachedChunk.java index c554b926..abc741a5 100644 --- a/src/main/java/baritone/cache/CachedChunk.java +++ b/src/main/java/baritone/cache/CachedChunk.java @@ -17,7 +17,6 @@ package baritone.cache; -import baritone.api.cache.IBlockTypeAccess; import baritone.utils.Helper; import baritone.utils.pathing.PathingBlockType; import net.minecraft.block.Block; @@ -31,7 +30,7 @@ import java.util.*; * @author Brady * @since 8/3/2018 1:04 AM */ -public final class CachedChunk implements IBlockTypeAccess, Helper { +public final class CachedChunk implements Helper { public static final Set BLOCKS_TO_KEEP_TRACK_OF; @@ -143,8 +142,7 @@ public final class CachedChunk implements IBlockTypeAccess, Helper { calculateHeightMap(); } - @Override - public final IBlockState getBlock(int x, int y, int z) { + public final IBlockState getBlock(int x, int y, int z, int dimension) { int internalPos = z << 4 | x; if (heightMap[internalPos] == y) { // we have this exact block, it's a surface block @@ -155,10 +153,10 @@ public final class CachedChunk implements IBlockTypeAccess, Helper { return overview[internalPos]; } PathingBlockType type = getType(x, y, z); - if (type == PathingBlockType.SOLID && y == 127 && mc.player.dimension == -1) { + if (type == PathingBlockType.SOLID && y == 127 && dimension == -1) { return Blocks.BEDROCK.getDefaultState(); } - return ChunkPacker.pathingTypeToBlock(type); + return ChunkPacker.pathingTypeToBlock(type, dimension); } private PathingBlockType getType(int x, int y, int z) { diff --git a/src/main/java/baritone/cache/CachedRegion.java b/src/main/java/baritone/cache/CachedRegion.java index c25139ac..95c20f37 100644 --- a/src/main/java/baritone/cache/CachedRegion.java +++ b/src/main/java/baritone/cache/CachedRegion.java @@ -59,22 +59,25 @@ public final class CachedRegion implements ICachedRegion { */ private final int z; + private final int dimension; + /** * Has this region been modified since its most recent load or save */ private boolean hasUnsavedChanges; - CachedRegion(int x, int z) { + CachedRegion(int x, int z, int dimension) { this.x = x; this.z = z; this.hasUnsavedChanges = false; + this.dimension = dimension; } @Override public final IBlockState getBlock(int x, int y, int z) { CachedChunk chunk = chunks[x >> 4][z >> 4]; if (chunk != null) { - return chunk.getBlock(x & 15, y, z & 15); + return chunk.getBlock(x & 15, y, z & 15, dimension); } return null; } diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java index 14b66839..b775902e 100644 --- a/src/main/java/baritone/cache/CachedWorld.java +++ b/src/main/java/baritone/cache/CachedWorld.java @@ -56,7 +56,9 @@ public final class CachedWorld implements ICachedWorld, Helper { private final LinkedBlockingQueue toPack = new LinkedBlockingQueue<>(); - CachedWorld(Path directory) { + private final int dimension; + + CachedWorld(Path directory, int dimension) { if (!Files.exists(directory)) { try { Files.createDirectories(directory); @@ -64,11 +66,12 @@ public final class CachedWorld implements ICachedWorld, Helper { } } this.directory = directory.toString(); + this.dimension = dimension; System.out.println("Cached world directory: " + directory); // Insert an invalid region element cachedRegions.put(0, null); - Baritone.INSTANCE.getExecutor().execute(new PackerThread()); - Baritone.INSTANCE.getExecutor().execute(() -> { + Baritone.getExecutor().execute(new PackerThread()); + Baritone.getExecutor().execute(() -> { try { Thread.sleep(30000); while (true) { @@ -165,6 +168,9 @@ public final class CachedWorld implements ICachedWorld, Helper { * Delete regions that are too far from the player */ private synchronized void prune() { + if (!Baritone.settings().pruneRegionsFromRAM.get()) { + return; + } BlockPos pruneCenter = guessPosition(); for (CachedRegion region : allRegions()) { if (region == null) { @@ -184,7 +190,7 @@ public final class CachedWorld implements ICachedWorld, Helper { * If we are still in this world and dimension, return player feet, otherwise return most recently modified chunk */ private BlockPos guessPosition() { - WorldData data = WorldProvider.INSTANCE.getCurrentWorld(); + WorldData data = Baritone.INSTANCE.getWorldProvider().getCurrentWorld(); if (data != null && data.getCachedWorld() == this) { return playerFeet(); } @@ -238,7 +244,7 @@ public final class CachedWorld implements ICachedWorld, Helper { */ private synchronized CachedRegion getOrCreateRegion(int regionX, int regionZ) { return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> { - CachedRegion newRegion = new CachedRegion(regionX, regionZ); + CachedRegion newRegion = new CachedRegion(regionX, regionZ, dimension); newRegion.load(this.directory); return newRegion; }); diff --git a/src/main/java/baritone/cache/ChunkPacker.java b/src/main/java/baritone/cache/ChunkPacker.java index e29bde00..d73cdb03 100644 --- a/src/main/java/baritone/cache/ChunkPacker.java +++ b/src/main/java/baritone/cache/ChunkPacker.java @@ -144,7 +144,7 @@ public final class ChunkPacker implements Helper { return PathingBlockType.SOLID; } - public static IBlockState pathingTypeToBlock(PathingBlockType type) { + public static IBlockState pathingTypeToBlock(PathingBlockType type, int dimension) { switch (type) { case AIR: return Blocks.AIR.getDefaultState(); @@ -154,7 +154,7 @@ public final class ChunkPacker implements Helper { return Blocks.LAVA.getDefaultState(); case SOLID: // Dimension solid types - switch (mc.player.dimension) { + switch (dimension) { case -1: return Blocks.NETHERRACK.getDefaultState(); case 0: diff --git a/src/main/java/baritone/cache/Waypoint.java b/src/main/java/baritone/cache/Waypoint.java index 00f4410a..19e574f9 100644 --- a/src/main/java/baritone/cache/Waypoint.java +++ b/src/main/java/baritone/cache/Waypoint.java @@ -42,9 +42,9 @@ public class Waypoint implements IWaypoint { * Constructor called when a Waypoint is read from disk, adds the creationTimestamp * as a parameter so that it is reserved after a waypoint is wrote to the disk. * - * @param name The waypoint name - * @param tag The waypoint tag - * @param location The waypoint location + * @param name The waypoint name + * @param tag The waypoint tag + * @param location The waypoint location * @param creationTimestamp When the waypoint was created */ Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { diff --git a/src/main/java/baritone/cache/WorldData.java b/src/main/java/baritone/cache/WorldData.java index b489d933..897a0d87 100644 --- a/src/main/java/baritone/cache/WorldData.java +++ b/src/main/java/baritone/cache/WorldData.java @@ -35,15 +35,17 @@ public class WorldData implements IWorldData { private final Waypoints waypoints; //public final MapData map; public final Path directory; + public final int dimension; - WorldData(Path directory) { + WorldData(Path directory, int dimension) { this.directory = directory; - this.cache = new CachedWorld(directory.resolve("cache")); + this.cache = new CachedWorld(directory.resolve("cache"), dimension); this.waypoints = new Waypoints(directory.resolve("waypoints")); + this.dimension = dimension; } public void onClose() { - Baritone.INSTANCE.getExecutor().execute(() -> { + Baritone.getExecutor().execute(() -> { System.out.println("Started saving the world in a new thread"); cache.save(); }); diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index 2aef54c6..dd6e3561 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -22,7 +22,6 @@ import baritone.api.cache.IWorldProvider; import baritone.utils.Helper; import baritone.utils.accessor.IAnvilChunkLoader; import baritone.utils.accessor.IChunkProviderServer; -import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.world.WorldServer; @@ -39,11 +38,9 @@ import java.util.function.Consumer; * @author Brady * @since 8/4/2018 11:06 AM */ -public enum WorldProvider implements IWorldProvider, Helper { +public class WorldProvider implements IWorldProvider, Helper { - INSTANCE; - - private final Map worldCache = new HashMap<>(); + private static final Map worldCache = new HashMap<>(); // this is how the bots have the same cached world private WorldData currentWorld; @@ -52,13 +49,20 @@ public enum WorldProvider implements IWorldProvider, Helper { return this.currentWorld; } - public final void initWorld(WorldClient world) { - int dimensionID = world.provider.getDimensionType().getId(); - File directory; - File readme; + /** + * Called when a new world is initialized to discover the + * + * @param dimension The ID of the world's dimension + */ + public final void initWorld(int dimension) { + // Fight me @leijurv + File directory, readme; + IntegratedServer integratedServer = mc.getIntegratedServer(); + + // If there is an integrated server running (Aka Singleplayer) then do magic to find the world save file if (integratedServer != null) { - WorldServer localServerWorld = integratedServer.getWorld(dimensionID); + WorldServer localServerWorld = integratedServer.getWorld(dimension); IChunkProviderServer provider = (IChunkProviderServer) localServerWorld.getChunkProvider(); IAnvilChunkLoader loader = (IAnvilChunkLoader) provider.getChunkLoader(); directory = loader.getChunkSaveLocation(); @@ -71,27 +75,27 @@ public enum WorldProvider implements IWorldProvider, Helper { directory = new File(directory, "baritone"); readme = directory; - - } else { - //remote - directory = new File(Baritone.INSTANCE.getDir(), mc.getCurrentServerData().serverIP); - readme = Baritone.INSTANCE.getDir(); + } else { // Otherwise, the server must be remote... + directory = new File(Baritone.getDir(), mc.getCurrentServerData().serverIP); + readme = Baritone.getDir(); } + // lol wtf is this baritone folder in my minecraft save? try (FileOutputStream out = new FileOutputStream(new File(readme, "readme.txt"))) { // good thing we have a readme out.write("https://github.com/cabaletta/baritone\n".getBytes()); } catch (IOException ignored) {} - directory = new File(directory, "DIM" + dimensionID); - Path dir = directory.toPath(); + // We will actually store the world data in a subfolder: "DIM" + Path dir = new File(directory, "DIM" + dimension).toPath(); if (!Files.exists(dir)) { try { Files.createDirectories(dir); } catch (IOException ignored) {} } + System.out.println("Baritone world data dir: " + dir); - this.currentWorld = this.worldCache.computeIfAbsent(dir, WorldData::new); + this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension)); } public final void closeWorld() { diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index 61756e33..084b5562 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -21,16 +21,12 @@ import baritone.Baritone; import baritone.api.event.events.*; import baritone.api.event.events.type.EventState; import baritone.api.event.listener.IGameEventListener; -import baritone.api.utils.interfaces.Toggleable; import baritone.cache.WorldProvider; -import baritone.utils.BlockStateInterface; import baritone.utils.Helper; -import baritone.utils.InputOverrideHandler; -import net.minecraft.client.settings.KeyBinding; import net.minecraft.world.chunk.Chunk; -import org.lwjgl.input.Keyboard; import java.util.ArrayList; +import java.util.List; /** * @author Brady @@ -38,57 +34,32 @@ import java.util.ArrayList; */ public final class GameEventHandler implements IGameEventListener, Helper { - private final ArrayList listeners = new ArrayList<>(); + private final Baritone baritone; + + private final List listeners = new ArrayList<>(); + + public GameEventHandler(Baritone baritone) { + this.baritone = baritone; + } @Override public final void onTick(TickEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onTick(event); - } - }); + listeners.forEach(l -> l.onTick(event)); } @Override public final void onPlayerUpdate(PlayerUpdateEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onPlayerUpdate(event); - } - }); + listeners.forEach(l -> l.onPlayerUpdate(event)); } @Override public final void onProcessKeyBinds() { - InputOverrideHandler inputHandler = Baritone.INSTANCE.getInputOverrideHandler(); - - // Simulate the key being held down this tick - for (InputOverrideHandler.Input input : InputOverrideHandler.Input.values()) { - KeyBinding keyBinding = input.getKeyBinding(); - - if (inputHandler.isInputForcedDown(keyBinding) && !keyBinding.isKeyDown()) { - int keyCode = keyBinding.getKeyCode(); - - if (keyCode < Keyboard.KEYBOARD_SIZE) { - KeyBinding.onTick(keyCode < 0 ? keyCode + 100 : keyCode); - } - } - } - - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onProcessKeyBinds(); - } - }); + listeners.forEach(IGameEventListener::onProcessKeyBinds); } @Override public final void onSendChatMessage(ChatEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onSendChatMessage(event); - } - }); + listeners.forEach(l -> l.onSendChatMessage(event)); } @Override @@ -107,108 +78,67 @@ public final class GameEventHandler implements IGameEventListener, Helper { && mc.world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ()); if (isPostPopulate || isPreUnload) { - WorldProvider.INSTANCE.ifWorldLoaded(world -> { + baritone.getWorldProvider().ifWorldLoaded(world -> { Chunk chunk = mc.world.getChunk(event.getX(), event.getZ()); world.getCachedWorld().queueForPacking(chunk); }); } - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onChunkEvent(event); - } - }); + listeners.forEach(l -> l.onChunkEvent(event)); } @Override public final void onRenderPass(RenderEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onRenderPass(event); - } - }); + listeners.forEach(l -> l.onRenderPass(event)); } @Override public final void onWorldEvent(WorldEvent event) { - WorldProvider cache = WorldProvider.INSTANCE; - - BlockStateInterface.clearCachedChunk(); + WorldProvider cache = baritone.getWorldProvider(); if (event.getState() == EventState.POST) { cache.closeWorld(); if (event.getWorld() != null) { - cache.initWorld(event.getWorld()); + cache.initWorld(event.getWorld().provider.getDimensionType().getId()); } } - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onWorldEvent(event); - } - }); + listeners.forEach(l -> l.onWorldEvent(event)); } @Override public final void onSendPacket(PacketEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onSendPacket(event); - } - }); + listeners.forEach(l -> l.onSendPacket(event)); } @Override public final void onReceivePacket(PacketEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onReceivePacket(event); - } - }); + listeners.forEach(l -> l.onReceivePacket(event)); } @Override public void onPlayerRotationMove(RotationMoveEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onPlayerRotationMove(event); - } - }); + listeners.forEach(l -> l.onPlayerRotationMove(event)); } @Override public void onBlockInteract(BlockInteractEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onBlockInteract(event); - } - }); + listeners.forEach(l -> l.onBlockInteract(event)); } @Override public void onPlayerDeath() { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onPlayerDeath(); - } - }); + listeners.forEach(IGameEventListener::onPlayerDeath); } @Override public void onPathEvent(PathEvent event) { - listeners.forEach(l -> { - if (canDispatch(l)) { - l.onPathEvent(event); - } - }); + listeners.forEach(l -> l.onPathEvent(event)); } public final void registerEventListener(IGameEventListener listener) { this.listeners.add(listener); } - private boolean canDispatch(IGameEventListener listener) { - return !(listener instanceof Toggleable) || ((Toggleable) listener).isEnabled(); - } } diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index f9a15e36..b9babdda 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -25,7 +25,6 @@ import baritone.api.utils.BetterBlockPos; import baritone.pathing.calc.openset.BinaryHeapOpenSet; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Moves; -import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import baritone.utils.pathing.BetterWorldBorder; import baritone.utils.pathing.MutableMoveResult; @@ -44,7 +43,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel private final CalculationContext calcContext; public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Optional> favoredPositions, CalculationContext context) { - super(startX, startY, startZ, goal); + super(startX, startY, startZ, goal, context); this.favoredPositions = favoredPositions; this.calcContext = context; } @@ -65,8 +64,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel } MutableMoveResult res = new MutableMoveResult(); HashSet favored = favoredPositions.orElse(null); - BetterWorldBorder worldBorder = new BetterWorldBorder(world().getWorldBorder()); - BlockStateInterface.clearCachedChunk(); + BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world().getWorldBorder()); long startTime = System.nanoTime() / 1000000L; boolean slowPath = Baritone.settings().slowPath.get(); if (slowPath) { @@ -95,12 +93,12 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel numNodes++; if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) { logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered"); - return Optional.of(new Path(startNode, currentNode, numNodes, goal)); + return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext)); } for (Moves moves : Moves.values()) { int newX = currentNode.x + moves.xOffset; int newZ = currentNode.z + moves.zOffset; - if ((newX >> 4 != currentNode.x >> 4 || newZ >> 4 != currentNode.z >> 4) && !BlockStateInterface.isLoaded(newX, newZ)) { + if ((newX >> 4 != currentNode.x >> 4 || newZ >> 4 != currentNode.z >> 4) && !calcContext.isLoaded(newX, newZ)) { // only need to check if the destination is a loaded chunk if it's in a different chunk than the start of the movement if (!moves.dynamicXZ) { // only increment the counter if the movement would have gone out of bounds guaranteed numEmptyChunk++; @@ -131,7 +129,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ); } if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) { - throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ); + throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset)); } long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z); if (favoring && favored.contains(hashCode)) { @@ -198,7 +196,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel System.out.println("But I'm going to do it anyway, because yolo"); } System.out.println("Path goes for " + Math.sqrt(dist) + " blocks"); - return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal)); + return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal, calcContext)); } } logDebug("Even with a cost coefficient of " + COEFFICIENTS[COEFFICIENTS.length - 1] + ", I couldn't get more than " + Math.sqrt(bestDist) + " blocks"); diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index bbbe32ad..79a56037 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -21,6 +21,8 @@ import baritone.Baritone; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.goals.Goal; +import baritone.api.utils.PathCalculationResult; +import baritone.pathing.movement.CalculationContext; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Optional; @@ -43,6 +45,8 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { protected final Goal goal; + private final CalculationContext context; + /** * @see Issue #107 */ @@ -70,11 +74,12 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { */ protected final static double MIN_DIST_PATH = 5; - AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal) { + AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal, CalculationContext context) { this.startX = startX; this.startY = startY; this.startZ = startZ; this.goal = goal; + this.context = context; this.map = new Long2ObjectOpenHashMap<>(Baritone.settings().pathingMapDefaultSize.value, Baritone.settings().pathingMapLoadFactor.get()); } @@ -82,16 +87,26 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { cancelRequested = true; } - public synchronized Optional calculate(long timeout) { + public synchronized PathCalculationResult calculate(long timeout) { if (isFinished) { throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!"); } this.cancelRequested = false; try { Optional path = calculate0(timeout); - path.ifPresent(IPath::postProcess); + path = path.map(IPath::postProcess); isFinished = true; - return path; + if (cancelRequested) { + return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, path); + } + if (!path.isPresent()) { + return new PathCalculationResult(PathCalculationResult.Type.FAILURE, path); + } + if (goal.isInGoal(path.get().getDest())) { + return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_TO_GOAL, path); + } else { + return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_SEGMENT, path); + } } finally { // this is run regardless of what exception may or may not be raised by calculate0 currentlyRunning = null; @@ -160,7 +175,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { @Override public Optional pathToMostRecentNodeConsidered() { try { - return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal)); + return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal, context)); } catch (IllegalStateException ex) { System.out.println("Unable to construct path to render"); return Optional.empty(); @@ -182,7 +197,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { } if (getDistFromStartSq(bestSoFar[i]) > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared try { - return Optional.of(new Path(startNode, bestSoFar[i], 0, goal)); + return Optional.of(new Path(startNode, bestSoFar[i], 0, goal, context)); } catch (IllegalStateException ex) { System.out.println("Unable to construct path to render"); return Optional.empty(); diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index adcd9b71..0b5b2cc7 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -17,16 +17,16 @@ package baritone.pathing.calc; -import baritone.api.BaritoneAPI; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; -import net.minecraft.client.Minecraft; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.chunk.EmptyChunk; +import baritone.pathing.path.CutoffPath; +import baritone.utils.Helper; +import baritone.utils.pathing.PathBase; import java.util.ArrayList; import java.util.Collections; @@ -38,7 +38,7 @@ import java.util.List; * * @author leijurv */ -class Path implements IPath { +class Path extends PathBase { /** * The start position of this path @@ -58,20 +58,26 @@ class Path implements IPath { private final List movements; + private final List nodes; + private final Goal goal; private final int numNodes; + private final CalculationContext context; + private volatile boolean verified; - Path(PathNode start, PathNode end, int numNodes, Goal goal) { + Path(PathNode start, PathNode end, int numNodes, Goal goal, CalculationContext context) { this.start = new BetterBlockPos(start.x, start.y, start.z); this.end = new BetterBlockPos(end.x, end.y, end.z); this.numNodes = numNodes; this.path = new ArrayList<>(); this.movements = new ArrayList<>(); + this.nodes = new ArrayList<>(); this.goal = goal; - assemblePath(start, end); + this.context = context; + assemblePath(end); } @Override @@ -80,88 +86,80 @@ class Path implements IPath { } /** - * Assembles this path given the start and end nodes. + * Assembles this path given the end node. * - * @param start The start node - * @param end The end node + * @param end The end node */ - private void assemblePath(PathNode start, PathNode end) { + private void assemblePath(PathNode end) { if (!path.isEmpty() || !movements.isEmpty()) { throw new IllegalStateException(); } PathNode current = end; LinkedList tempPath = new LinkedList<>(); + LinkedList tempNodes = new LinkedList(); // Repeatedly inserting to the beginning of an arraylist is O(n^2) // Instead, do it into a linked list, then convert at the end - while (!current.equals(start)) { + while (current != null) { + tempNodes.addFirst(current); tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z)); current = current.previous; } - tempPath.addFirst(this.start); // Can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is // inserting into a LinkedList keeps track of length, then when we addall (which calls .toArray) it's able // to performantly do that conversion since it knows the length. path.addAll(tempPath); + nodes.addAll(tempNodes); } - /** - * Performs a series of checks to ensure that the assembly of the path went as expected. - */ - private void sanityCheck() { - if (!start.equals(path.get(0))) { - throw new IllegalStateException("Start node does not equal first path element"); - } - if (!end.equals(path.get(path.size() - 1))) { - throw new IllegalStateException("End node does not equal last path element"); - } - if (path.size() != movements.size() + 1) { - throw new IllegalStateException("Size of path array is unexpected"); - } - for (int i = 0; i < path.size() - 1; i++) { - BlockPos src = path.get(i); - BlockPos dest = path.get(i + 1); - Movement movement = movements.get(i); - if (!src.equals(movement.getSrc())) { - throw new IllegalStateException("Path source is not equal to the movement source"); - } - if (!dest.equals(movement.getDest())) { - throw new IllegalStateException("Path destination is not equal to the movement destination"); - } - } - } - - private void assembleMovements() { + private boolean assembleMovements() { if (path.isEmpty() || !movements.isEmpty()) { throw new IllegalStateException(); } for (int i = 0; i < path.size() - 1; i++) { - movements.add(runBackwards(path.get(i), path.get(i + 1))); + double cost = nodes.get(i + 1).cost - nodes.get(i).cost; + Movement move = runBackwards(path.get(i), path.get(i + 1), cost); + if (move == null) { + return true; + } else { + movements.add(move); + } } + return false; } - private static Movement runBackwards(BetterBlockPos src, BetterBlockPos dest) { // TODO this is horrifying + private Movement runBackwards(BetterBlockPos src, BetterBlockPos dest, double cost) { for (Moves moves : Moves.values()) { - Movement move = moves.apply0(src); + Movement move = moves.apply0(context, src); if (move.getDest().equals(dest)) { - // TODO instead of recalculating here, could we take pathNode.cost - pathNode.prevNode.cost to get the cost as-calculated? - move.recalculateCost(); // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution + // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution + move.override(cost); return move; } } // this is no longer called from bestPathSoFar, now it's in postprocessing - throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src)); + Helper.HELPER.logDebug("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src)); + return null; } @Override - public void postProcess() { + public IPath postProcess() { if (verified) { throw new IllegalStateException(); } verified = true; - assembleMovements(); + boolean failed = assembleMovements(); + movements.forEach(m -> m.checkLoadedChunk(context)); + + if (failed) { // at least one movement became impossible during calculation + CutoffPath res = new CutoffPath(this, movements().size()); + if (res.movements().size() != movements.size()) { + throw new IllegalStateException(); + } + return res; + } // more post processing here - movements.forEach(Movement::checkLoadedChunk); sanityCheck(); + return this; } @Override @@ -191,28 +189,4 @@ class Path implements IPath { public BetterBlockPos getDest() { return end; } - - @Override - public IPath cutoffAtLoadedChunks() { - for (int i = 0; i < positions().size(); i++) { - BlockPos pos = positions().get(i); - if (Minecraft.getMinecraft().world.getChunk(pos) instanceof EmptyChunk) { - return new CutoffPath(this, i); - } - } - return this; - } - - @Override - public IPath staticCutoff(Goal destination) { - if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) { - return this; - } - if (destination == null || destination.isInGoal(getDest())) { - return this; - } - double factor = BaritoneAPI.getSettings().pathCutoffFactor.get(); - int newLength = (int) (length() * factor); - return new CutoffPath(this, newLength); - } } diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index 00c063af..e419bb72 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -19,22 +19,33 @@ package baritone.pathing.movement; import baritone.Baritone; import baritone.api.pathing.movement.ActionCosts; +import baritone.cache.WorldData; +import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import baritone.utils.ToolSet; import baritone.utils.pathing.BetterWorldBorder; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; /** * @author Brady * @since 8/7/2018 4:30 PM */ -public class CalculationContext implements Helper { +public class CalculationContext { private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET); + private final EntityPlayerSP player; + private final World world; + private final WorldData worldData; + private final BlockStateInterface bsi; private final ToolSet toolSet; private final boolean hasWaterBucket; private final boolean hasThrowaway; @@ -48,19 +59,20 @@ public class CalculationContext implements Helper { private final BetterWorldBorder worldBorder; public CalculationContext() { - this(new ToolSet()); - } - - public CalculationContext(ToolSet toolSet) { - this.toolSet = toolSet; + this.player = Helper.HELPER.player(); + this.world = Helper.HELPER.world(); + this.worldData = Baritone.INSTANCE.getWorldProvider().getCurrentWorld(); + this.bsi = new BlockStateInterface(world, worldData); // TODO TODO TODO + // new CalculationContext() needs to happen, can't add an argument (i'll beat you), can we get the world provider from currentlyTicking? + this.toolSet = new ToolSet(player); this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(false); - this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_WATER)) && !world().provider.isNether(); - this.canSprint = Baritone.settings().allowSprint.get() && player().getFoodStats().getFoodLevel() > 6; + this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether(); + this.canSprint = Baritone.settings().allowSprint.get() && player.getFoodStats().getFoodLevel() > 6; this.placeBlockCost = Baritone.settings().blockPlacementPenalty.get(); this.allowBreak = Baritone.settings().allowBreak.get(); this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.get(); this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.get(); - int depth = EnchantmentHelper.getDepthStriderModifier(player()); + int depth = EnchantmentHelper.getDepthStriderModifier(player); if (depth > 3) { depth = 3; } @@ -70,7 +82,23 @@ public class CalculationContext implements Helper { // why cache these things here, why not let the movements just get directly from settings? // because if some movements are calculated one way and others are calculated another way, // then you get a wildly inconsistent path that isn't optimal for either scenario. - this.worldBorder = new BetterWorldBorder(world().getWorldBorder()); + this.worldBorder = new BetterWorldBorder(world.getWorldBorder()); + } + + public IBlockState get(int x, int y, int z) { + return bsi.get0(x, y, z); // laughs maniacally + } + + public boolean isLoaded(int x, int z) { + return bsi.isLoaded(x, z); + } + + public IBlockState get(BlockPos pos) { + return get(pos.getX(), pos.getY(), pos.getZ()); + } + + public Block getBlock(int x, int y, int z) { + return get(x, y, z).getBlock(); } public boolean canPlaceThrowawayAt(int x, int y, int z) { @@ -95,6 +123,22 @@ public class CalculationContext implements Helper { return false; } + public World world() { + return world; + } + + public EntityPlayerSP player() { + return player; + } + + public BlockStateInterface bsi() { + return bsi; + } + + public WorldData worldData() { + return worldData; + } + public ToolSet getToolSet() { return toolSet; } diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index a2edb2c9..e492a795 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -20,22 +20,18 @@ package baritone.pathing.movement; import baritone.Baritone; import baritone.api.pathing.movement.IMovement; import baritone.api.pathing.movement.MovementStatus; -import baritone.api.utils.BetterBlockPos; -import baritone.api.utils.Rotation; -import baritone.api.utils.RotationUtils; -import baritone.api.utils.VecUtils; -import baritone.utils.BlockBreakHelper; +import baritone.api.utils.*; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import baritone.utils.InputOverrideHandler; import net.minecraft.block.BlockLiquid; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.chunk.EmptyChunk; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import static baritone.utils.InputOverrideHandler.Input; @@ -60,8 +56,6 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { */ protected final BetterBlockPos positionToPlace; - private boolean didBreakLastTick; - private Double cost; public List toBreakCached = null; @@ -97,7 +91,7 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { return getCost(); } - protected void override(double cost) { + public void override(double cost) { this.cost = cost; } @@ -115,52 +109,31 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { @Override public MovementStatus update() { player().capabilities.isFlying = false; - MovementState latestState = updateState(currentState); - if (BlockStateInterface.isLiquid(playerFeet())) { - latestState.setInput(Input.JUMP, true); + currentState = updateState(currentState); + if (MovementHelper.isLiquid(playerFeet())) { + currentState.setInput(Input.JUMP, true); } if (player().isEntityInsideOpaqueBlock()) { - latestState.setInput(Input.CLICK_LEFT, true); + currentState.setInput(Input.CLICK_LEFT, true); } // If the movement target has to force the new rotations, or we aren't using silent move, then force the rotations - latestState.getTarget().getRotation().ifPresent(rotation -> + currentState.getTarget().getRotation().ifPresent(rotation -> Baritone.INSTANCE.getLookBehavior().updateTarget( rotation, - latestState.getTarget().hasToForceRotations())); + currentState.getTarget().hasToForceRotations())); // TODO: calculate movement inputs from latestState.getGoal().position // latestState.getTarget().position.ifPresent(null); NULL CONSUMER REALLY SHOULDN'T BE THE FINAL THING YOU SHOULD REALLY REPLACE THIS WITH ALMOST ACTUALLY ANYTHING ELSE JUST PLEASE DON'T LEAVE IT AS IT IS THANK YOU KANYE - this.didBreakLastTick = false; - - latestState.getInputStates().forEach((input, forced) -> { - if (Baritone.settings().leftClickWorkaround.get()) { - RayTraceResult trace = mc.objectMouseOver; - boolean isBlockTrace = trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK; - boolean isLeftClick = forced && input == Input.CLICK_LEFT; - - // If we're forcing left click, we're in a gui screen, and we're looking - // at a block, break the block without a direct game input manipulation. - if (mc.currentScreen != null && isLeftClick && isBlockTrace) { - BlockBreakHelper.tryBreakBlock(trace.getBlockPos(), trace.sideHit); - this.didBreakLastTick = true; - return; - } - } + currentState.getInputStates().forEach((input, forced) -> { Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced); }); - latestState.getInputStates().replaceAll((input, forced) -> false); - - if (!this.didBreakLastTick) { - BlockBreakHelper.stopBreakingBlock(); - } - - currentState = latestState; + currentState.getInputStates().replaceAll((input, forced) -> false); // If the current status indicates a completed movement if (currentState.getStatus().isComplete()) { - onFinish(latestState); + Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); } return currentState.getStatus(); @@ -174,10 +147,13 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { for (BetterBlockPos blockPos : positionsToBreak) { if (!MovementHelper.canWalkThrough(blockPos) && !(BlockStateInterface.getBlock(blockPos) instanceof BlockLiquid)) { // can't break liquid, so don't try somethingInTheWay = true; - Optional reachable = RotationUtils.reachable(player(), blockPos); + Optional reachable = RotationUtils.reachable(player(), blockPos, playerController().getBlockReachDistance()); if (reachable.isPresent()) { MovementHelper.switchToBestToolFor(BlockStateInterface.get(blockPos)); - state.setTarget(new MovementState.MovementTarget(reachable.get(), true)).setInput(Input.CLICK_LEFT, true); + state.setTarget(new MovementState.MovementTarget(reachable.get(), true)); + if (Objects.equals(RayTraceUtils.getSelectedBlock().orElse(null), blockPos)) { + state.setInput(Input.CLICK_LEFT, true); + } return false; } //get rekt minecraft @@ -186,7 +162,9 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { //you dont own me!!!! state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(player().getPositionEyes(1.0F), VecUtils.getBlockPosCenter(blockPos)), true) - ).setInput(InputOverrideHandler.Input.CLICK_LEFT, 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(InputOverrideHandler.Input.CLICK_LEFT, true); return false; } } @@ -218,20 +196,6 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { return dest; } - /** - * Run cleanup on state finish and declare success. - */ - public void onFinish(MovementState state) { - state.getInputStates().replaceAll((input, forced) -> false); - state.getInputStates().forEach((input, forced) -> Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced)); - } - - public void cancel() { - currentState.getInputStates().replaceAll((input, forced) -> false); - currentState.getInputStates().forEach((input, forced) -> Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced)); - currentState.setStatus(MovementStatus.CANCELED); - } - @Override public void reset() { currentState = new MovementState().setStatus(MovementStatus.PREPPING); @@ -262,8 +226,8 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { return getDest().subtract(getSrc()); } - public void checkLoadedChunk() { - calculatedWhileLoaded = !(world().getChunk(getDest()) instanceof EmptyChunk); + public void checkLoadedChunk(CalculationContext context) { + calculatedWhileLoaded = !(context.world().getChunk(getDest()) instanceof EmptyChunk); } @Override diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index d887a714..a7e9c378 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -28,7 +28,6 @@ import baritone.utils.ToolSet; import net.minecraft.block.*; import net.minecraft.block.properties.PropertyBool; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.init.Blocks; import net.minecraft.item.ItemPickaxe; @@ -45,16 +44,16 @@ import net.minecraft.world.chunk.EmptyChunk; */ public interface MovementHelper extends ActionCosts, Helper { - static boolean avoidBreaking(int x, int y, int z, IBlockState state) { + static boolean avoidBreaking(CalculationContext context, int x, int y, int z, IBlockState state) { Block b = state.getBlock(); return b == Blocks.ICE // ice becomes water, and water can mess up the path || b instanceof BlockSilverfish // obvious reasons - // call BlockStateInterface.get directly with x,y,z. no need to make 5 new BlockPos for no reason - || BlockStateInterface.get(x, y + 1, z).getBlock() instanceof BlockLiquid//don't break anything touching liquid on any side - || BlockStateInterface.get(x + 1, y, z).getBlock() instanceof BlockLiquid - || BlockStateInterface.get(x - 1, y, z).getBlock() instanceof BlockLiquid - || BlockStateInterface.get(x, y, z + 1).getBlock() instanceof BlockLiquid - || BlockStateInterface.get(x, y, z - 1).getBlock() instanceof BlockLiquid; + // call context.get directly with x,y,z. no need to make 5 new BlockPos for no reason + || context.get(x, y + 1, z).getBlock() instanceof BlockLiquid//don't break anything touching liquid on any side + || context.get(x + 1, y, z).getBlock() instanceof BlockLiquid + || context.get(x - 1, y, z).getBlock() instanceof BlockLiquid + || context.get(x, y, z + 1).getBlock() instanceof BlockLiquid + || context.get(x, y, z - 1).getBlock() instanceof BlockLiquid; } /** @@ -64,14 +63,14 @@ public interface MovementHelper extends ActionCosts, Helper { * @return */ static boolean canWalkThrough(BetterBlockPos pos) { - return canWalkThrough(pos.x, pos.y, pos.z, BlockStateInterface.get(pos)); + return canWalkThrough(new CalculationContext(), pos.x, pos.y, pos.z, BlockStateInterface.get(pos)); } - static boolean canWalkThrough(int x, int y, int z) { - return canWalkThrough(x, y, z, BlockStateInterface.get(x, y, z)); + static boolean canWalkThrough(CalculationContext context, int x, int y, int z) { + return canWalkThrough(context, x, y, z, context.get(x, y, z)); } - static boolean canWalkThrough(int x, int y, int z, IBlockState state) { + static boolean canWalkThrough(CalculationContext context, int x, int y, int z, IBlockState state) { Block block = state.getBlock(); if (block == Blocks.AIR) { // early return for most common case return true; @@ -105,14 +104,14 @@ public interface MovementHelper extends ActionCosts, Helper { } throw new IllegalStateException(); } - if (BlockStateInterface.isFlowing(state)) { + if (isFlowing(state)) { return false; // Don't walk through flowing liquids } if (block instanceof BlockLiquid) { if (Baritone.settings().assumeWalkOnWater.get()) { return false; } - IBlockState up = BlockStateInterface.get(x, y + 1, z); + IBlockState up = context.get(x, y + 1, z); if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) { return false; } @@ -130,8 +129,8 @@ public interface MovementHelper extends ActionCosts, Helper { * * @return */ - static boolean fullyPassable(int x, int y, int z) { - return fullyPassable(BlockStateInterface.get(x, y, z)); + static boolean fullyPassable(CalculationContext context, int x, int y, int z) { + return fullyPassable(context.get(x, y, z)); } static boolean fullyPassable(IBlockState state) { @@ -246,7 +245,7 @@ public interface MovementHelper extends ActionCosts, Helper { * * @return */ - static boolean canWalkOn(int x, int y, int z, IBlockState state) { + static boolean canWalkOn(CalculationContext context, int x, int y, int z, IBlockState state) { Block block = state.getBlock(); if (block == Blocks.AIR || block == Blocks.MAGMA) { // early return for most common case (air) @@ -254,9 +253,6 @@ public interface MovementHelper extends ActionCosts, Helper { return false; } if (state.isBlockNormalCube()) { - if (BlockStateInterface.isLava(block) || BlockStateInterface.isWater(block)) { - throw new IllegalStateException(); - } return true; } if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.get())) { // TODO reconsider this @@ -268,20 +264,20 @@ public interface MovementHelper extends ActionCosts, Helper { if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST) { return true; } - if (BlockStateInterface.isWater(block)) { + if (isWater(block)) { // since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()" // BlockPos s that we'd just garbage collect immediately is actually noticeable. I don't even think its a decrease in readability - Block up = BlockStateInterface.get(x, y + 1, z).getBlock(); + Block up = context.get(x, y + 1, z).getBlock(); if (up == Blocks.WATERLILY) { return true; } - if (BlockStateInterface.isFlowing(state) || block == Blocks.FLOWING_WATER) { + if (isFlowing(state) || block == Blocks.FLOWING_WATER) { // the only scenario in which we can walk on flowing water is if it's under still water with jesus off - return BlockStateInterface.isWater(up) && !Baritone.settings().assumeWalkOnWater.get(); + return isWater(up) && !Baritone.settings().assumeWalkOnWater.get(); } // if assumeWalkOnWater is on, we can only walk on water if there isn't water above it // if assumeWalkOnWater is off, we can only walk on water if there is water above it - return BlockStateInterface.isWater(up) ^ Baritone.settings().assumeWalkOnWater.get(); + return isWater(up) ^ Baritone.settings().assumeWalkOnWater.get(); } if (block instanceof BlockGlass || block instanceof BlockStainedGlass) { return true; @@ -299,19 +295,19 @@ public interface MovementHelper extends ActionCosts, Helper { } static boolean canWalkOn(BetterBlockPos pos, IBlockState state) { - return canWalkOn(pos.x, pos.y, pos.z, state); + return canWalkOn(new CalculationContext(), pos.x, pos.y, pos.z, state); } static boolean canWalkOn(BetterBlockPos pos) { - return canWalkOn(pos.x, pos.y, pos.z, BlockStateInterface.get(pos)); + return canWalkOn(new CalculationContext(), pos.x, pos.y, pos.z, BlockStateInterface.get(pos)); } - static boolean canWalkOn(int x, int y, int z) { - return canWalkOn(x, y, z, BlockStateInterface.get(x, y, z)); + static boolean canWalkOn(CalculationContext context, int x, int y, int z) { + return canWalkOn(context, x, y, z, context.get(x, y, z)); } - static boolean canPlaceAgainst(int x, int y, int z) { - return canPlaceAgainst(BlockStateInterface.get(x, y, z)); + static boolean canPlaceAgainst(CalculationContext context, int x, int y, int z) { + return canPlaceAgainst(context.get(x, y, z)); } static boolean canPlaceAgainst(BlockPos pos) { @@ -324,16 +320,16 @@ public interface MovementHelper extends ActionCosts, Helper { } static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, boolean includeFalling) { - return getMiningDurationTicks(context, x, y, z, BlockStateInterface.get(x, y, z), includeFalling); + return getMiningDurationTicks(context, x, y, z, context.get(x, y, z), includeFalling); } static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) { Block block = state.getBlock(); - if (!canWalkThrough(x, y, z, state)) { + if (!canWalkThrough(context, x, y, z, state)) { if (!context.canBreakAt(x, y, z)) { return COST_INF; } - if (avoidBreaking(x, y, z, state)) { + if (avoidBreaking(context, x, y, z, state)) { return COST_INF; } if (block instanceof BlockLiquid) { @@ -348,7 +344,7 @@ public interface MovementHelper extends ActionCosts, Helper { double result = m / strVsBlock; result += context.breakBlockAdditionalCost(); if (includeFalling) { - IBlockState above = BlockStateInterface.get(x, y + 1, z); + IBlockState above = context.get(x, y + 1, z); if (above.getBlock() instanceof BlockFalling) { result += getMiningDurationTicks(context, x, y + 1, z, above, true); } @@ -364,10 +360,6 @@ public interface MovementHelper extends ActionCosts, Helper { && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM; } - static boolean isBottomSlab(BlockPos pos) { - return isBottomSlab(BlockStateInterface.get(pos)); - } - /** * AutoTool */ @@ -387,7 +379,7 @@ public interface MovementHelper extends ActionCosts, Helper { * @param b the blockstate to mine */ static void switchToBestToolFor(IBlockState b) { - switchToBestToolFor(b, new ToolSet()); + switchToBestToolFor(b, new ToolSet(Helper.HELPER.player())); } /** @@ -397,11 +389,11 @@ public interface MovementHelper extends ActionCosts, Helper { * @param ts previously calculated ToolSet */ static void switchToBestToolFor(IBlockState b, ToolSet ts) { - mc.player.inventory.currentItem = ts.getBestSlot(b.getBlock()); + Helper.HELPER.player().inventory.currentItem = ts.getBestSlot(b.getBlock()); } static boolean throwaway(boolean select) { - EntityPlayerSP p = Minecraft.getMinecraft().player; + EntityPlayerSP p = Helper.HELPER.player(); NonNullList inv = p.inventory.mainInventory; for (byte i = 0; i < 9; i++) { ItemStack item = inv.get(i); @@ -437,11 +429,55 @@ public interface MovementHelper extends ActionCosts, Helper { } static void moveTowards(MovementState state, BlockPos pos) { + EntityPlayerSP player = Helper.HELPER.player(); state.setTarget(new MovementTarget( - new Rotation(RotationUtils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), + new Rotation(RotationUtils.calcRotationFromVec3d(player.getPositionEyes(1.0F), VecUtils.getBlockPosCenter(pos), - new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)).getYaw(), mc.player.rotationPitch), + new Rotation(player.rotationYaw, player.rotationPitch)).getYaw(), player.rotationPitch), false )).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); } + + /** + * Returns whether or not the specified block is + * water, regardless of whether or not it is flowing. + * + * @param b The block + * @return Whether or not the block is water + */ + static boolean isWater(Block b) { + return b == Blocks.FLOWING_WATER || b == Blocks.WATER; + } + + /** + * Returns whether or not the block at the specified pos is + * water, regardless of whether or not it is flowing. + * + * @param bp The block pos + * @return Whether or not the block is water + */ + static boolean isWater(BlockPos bp) { + return isWater(BlockStateInterface.getBlock(bp)); + } + + static boolean isLava(Block b) { + return b == Blocks.FLOWING_LAVA || b == Blocks.LAVA; + } + + /** + * Returns whether or not the specified pos has a liquid + * + * @param p The pos + * @return Whether or not the block is a liquid + */ + static boolean isLiquid(BlockPos p) { + return BlockStateInterface.getBlock(p) instanceof BlockLiquid; + } + + static boolean isFlowing(IBlockState state) { + // Will be IFluidState in 1.13 + return state.getBlock() instanceof BlockLiquid + && state.getPropertyKeys().contains(BlockLiquid.LEVEL) + && state.getValue(BlockLiquid.LEVEL) != 0; + } } diff --git a/src/main/java/baritone/pathing/movement/Moves.java b/src/main/java/baritone/pathing/movement/Moves.java index 80a6c4d5..340122b3 100644 --- a/src/main/java/baritone/pathing/movement/Moves.java +++ b/src/main/java/baritone/pathing/movement/Moves.java @@ -30,7 +30,7 @@ import net.minecraft.util.EnumFacing; public enum Moves { DOWNWARD(0, -1, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementDownward(src, src.down()); } @@ -42,7 +42,7 @@ public enum Moves { PILLAR(0, +1, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementPillar(src, src.up()); } @@ -54,7 +54,7 @@ public enum Moves { TRAVERSE_NORTH(0, 0, -1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementTraverse(src, src.north()); } @@ -66,7 +66,7 @@ public enum Moves { TRAVERSE_SOUTH(0, 0, +1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementTraverse(src, src.south()); } @@ -78,7 +78,7 @@ public enum Moves { TRAVERSE_EAST(+1, 0, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementTraverse(src, src.east()); } @@ -90,7 +90,7 @@ public enum Moves { TRAVERSE_WEST(-1, 0, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementTraverse(src, src.west()); } @@ -102,7 +102,7 @@ public enum Moves { ASCEND_NORTH(0, +1, -1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z - 1)); } @@ -114,7 +114,7 @@ public enum Moves { ASCEND_SOUTH(0, +1, +1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z + 1)); } @@ -126,7 +126,7 @@ public enum Moves { ASCEND_EAST(+1, +1, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementAscend(src, new BetterBlockPos(src.x + 1, src.y + 1, src.z)); } @@ -138,7 +138,7 @@ public enum Moves { ASCEND_WEST(-1, +1, 0) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementAscend(src, new BetterBlockPos(src.x - 1, src.y + 1, src.z)); } @@ -150,9 +150,9 @@ public enum Moves { DESCEND_EAST(+1, -1, 0, false, true) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { MutableMoveResult res = new MutableMoveResult(); - apply(new CalculationContext(), src.x, src.y, src.z, res); + apply(context, src.x, src.y, src.z, res); if (res.y == src.y - 1) { return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z)); } else { @@ -168,9 +168,9 @@ public enum Moves { DESCEND_WEST(-1, -1, 0, false, true) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { MutableMoveResult res = new MutableMoveResult(); - apply(new CalculationContext(), src.x, src.y, src.z, res); + apply(context, src.x, src.y, src.z, res); if (res.y == src.y - 1) { return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z)); } else { @@ -186,9 +186,9 @@ public enum Moves { DESCEND_NORTH(0, -1, -1, false, true) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { MutableMoveResult res = new MutableMoveResult(); - apply(new CalculationContext(), src.x, src.y, src.z, res); + apply(context, src.x, src.y, src.z, res); if (res.y == src.y - 1) { return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z)); } else { @@ -204,9 +204,9 @@ public enum Moves { DESCEND_SOUTH(0, -1, +1, false, true) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { MutableMoveResult res = new MutableMoveResult(); - apply(new CalculationContext(), src.x, src.y, src.z, res); + apply(context, src.x, src.y, src.z, res); if (res.y == src.y - 1) { return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z)); } else { @@ -222,7 +222,7 @@ public enum Moves { DIAGONAL_NORTHEAST(+1, 0, -1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.EAST); } @@ -234,7 +234,7 @@ public enum Moves { DIAGONAL_NORTHWEST(-1, 0, -1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.WEST); } @@ -246,7 +246,7 @@ public enum Moves { DIAGONAL_SOUTHEAST(+1, 0, +1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.EAST); } @@ -258,7 +258,7 @@ public enum Moves { DIAGONAL_SOUTHWEST(-1, 0, +1) { @Override - public Movement apply0(BetterBlockPos src) { + public Movement apply0(CalculationContext context, BetterBlockPos src) { return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.WEST); } @@ -270,8 +270,8 @@ public enum Moves { PARKOUR_NORTH(0, 0, -4, true, false) { @Override - public Movement apply0(BetterBlockPos src) { - return MovementParkour.cost(new CalculationContext(), src, EnumFacing.NORTH); + public Movement apply0(CalculationContext context, BetterBlockPos src) { + return MovementParkour.cost(context, src, EnumFacing.NORTH); } @Override @@ -282,8 +282,8 @@ public enum Moves { PARKOUR_SOUTH(0, 0, +4, true, false) { @Override - public Movement apply0(BetterBlockPos src) { - return MovementParkour.cost(new CalculationContext(), src, EnumFacing.SOUTH); + public Movement apply0(CalculationContext context, BetterBlockPos src) { + return MovementParkour.cost(context, src, EnumFacing.SOUTH); } @Override @@ -294,8 +294,8 @@ public enum Moves { PARKOUR_EAST(+4, 0, 0, true, false) { @Override - public Movement apply0(BetterBlockPos src) { - return MovementParkour.cost(new CalculationContext(), src, EnumFacing.EAST); + public Movement apply0(CalculationContext context, BetterBlockPos src) { + return MovementParkour.cost(context, src, EnumFacing.EAST); } @Override @@ -306,8 +306,8 @@ public enum Moves { PARKOUR_WEST(-4, 0, 0, true, false) { @Override - public Movement apply0(BetterBlockPos src) { - return MovementParkour.cost(new CalculationContext(), src, EnumFacing.WEST); + public Movement apply0(CalculationContext context, BetterBlockPos src) { + return MovementParkour.cost(context, src, EnumFacing.WEST); } @Override @@ -335,7 +335,7 @@ public enum Moves { this(x, y, z, false, false); } - public abstract Movement apply0(BetterBlockPos src); + public abstract Movement apply0(CalculationContext context, BetterBlockPos src); public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { if (dynamicXZ || dynamicY) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index e0d41047..1d161554 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -58,24 +58,24 @@ public class MovementAscend extends Movement { } public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { - IBlockState srcDown = BlockStateInterface.get(x, y - 1, z); + IBlockState srcDown = context.get(x, y - 1, z); if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) { return COST_INF; } // we can jump from soul sand, but not from a bottom slab boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown); - IBlockState toPlace = BlockStateInterface.get(destX, y, destZ); + IBlockState toPlace = context.get(destX, y, destZ); boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace); if (jumpingFromBottomSlab && !jumpingToBottomSlab) { return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab } boolean hasToPlace = false; - if (!MovementHelper.canWalkOn(destX, y, destZ, toPlace)) { + if (!MovementHelper.canWalkOn(context, destX, y, destZ, toPlace)) { if (!context.canPlaceThrowawayAt(destX, y, destZ)) { return COST_INF; } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace)) { + if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace)) { return COST_INF; } // TODO: add ability to place against .down() as well as the cardinal directions @@ -87,7 +87,7 @@ public class MovementAscend extends Movement { if (againstX == x && againstZ == z) { continue; } - if (MovementHelper.canPlaceAgainst(againstX, y, againstZ)) { + if (MovementHelper.canPlaceAgainst(context, againstX, y, againstZ)) { hasToPlace = true; break; } @@ -97,7 +97,7 @@ public class MovementAscend extends Movement { } } IBlockState srcUp2 = null; - if (BlockStateInterface.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(x, y + 1, z) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us + if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context, x, y + 1, z) || !((srcUp2 = context.get(x, y + 2, z)).getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us // HOWEVER, we assume that we're standing in the start position // that means that src and src.up(1) are both air // maybe they aren't now, but they will be by the time this starts @@ -138,7 +138,7 @@ public class MovementAscend extends Movement { totalCost += context.placeBlockCost(); } if (srcUp2 == null) { - srcUp2 = BlockStateInterface.get(x, y + 2, z); + srcUp2 = context.get(x, y + 2, z); } totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false); // TODO MAKE ABSOLUTELY SURE we don't need includeFalling here, from the falling check above if (totalCost >= COST_INF) { @@ -204,7 +204,7 @@ public class MovementAscend extends Movement { return state.setStatus(MovementStatus.UNREACHABLE); } MovementHelper.moveTowards(state, dest); - if (MovementHelper.isBottomSlab(jumpingOnto) && !MovementHelper.isBottomSlab(src.down())) { + if (MovementHelper.isBottomSlab(jumpingOnto) && !MovementHelper.isBottomSlab(BlockStateInterface.get(src.down()))) { return state; // don't jump while walking from a non double slab into a bottom slab } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index 5fb78d74..84f0d781 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -24,7 +24,6 @@ import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; -import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.pathing.MutableMoveResult; import net.minecraft.block.Block; @@ -58,13 +57,13 @@ public class MovementDescend extends Movement { } public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) { - Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock(); + Block fromDown = context.get(x, y - 1, z).getBlock(); if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { return; } double totalCost = 0; - IBlockState destDown = BlockStateInterface.get(destX, y - 1, destZ); + IBlockState destDown = context.get(destX, y - 1, destZ); totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false); if (totalCost >= COST_INF) { return; @@ -88,8 +87,8 @@ public class MovementDescend extends Movement { //A is plausibly breakable by either descend or fall //C, D, etc determine the length of the fall - IBlockState below = BlockStateInterface.get(destX, y - 2, destZ); - if (!MovementHelper.canWalkOn(destX, y - 2, destZ, below)) { + IBlockState below = context.get(destX, y - 2, destZ); + if (!MovementHelper.canWalkOn(context, destX, y - 2, destZ, below)) { dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res); return; } @@ -112,13 +111,13 @@ public class MovementDescend extends Movement { } public static void dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) { - if (frontBreak != 0 && BlockStateInterface.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) { + if (frontBreak != 0 && context.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) { // if frontBreak is 0 we can actually get through this without updating the falling block and making it actually fall // but if frontBreak is nonzero, we're breaking blocks in front, so don't let anything fall through this column, // and potentially replace the water we're going to fall into return; } - if (!MovementHelper.canWalkThrough(destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) { + if (!MovementHelper.canWalkThrough(context, destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) { return; } for (int fallHeight = 3; true; fallHeight++) { @@ -128,9 +127,9 @@ public class MovementDescend extends Movement { // this check prevents it from getting the block at y=-1 and crashing return; } - IBlockState ontoBlock = BlockStateInterface.get(destX, newY, destZ); + IBlockState ontoBlock = context.get(destX, newY, destZ); double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak; - if (ontoBlock.getBlock() == Blocks.WATER && !BlockStateInterface.isFlowing(ontoBlock) && BlockStateInterface.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here? + if (ontoBlock.getBlock() == Blocks.WATER && !MovementHelper.isFlowing(ontoBlock) && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here? // lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad // however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works) if (Baritone.settings().assumeWalkOnWater.get()) { @@ -146,10 +145,10 @@ public class MovementDescend extends Movement { if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) { return; } - if (MovementHelper.canWalkThrough(destX, newY, destZ, ontoBlock)) { + if (MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) { continue; } - if (!MovementHelper.canWalkOn(destX, newY, destZ, ontoBlock)) { + if (!MovementHelper.canWalkOn(context, destX, newY, destZ, ontoBlock)) { return; } if (MovementHelper.isBottomSlab(ontoBlock)) { @@ -183,7 +182,7 @@ public class MovementDescend extends Movement { } BlockPos playerFeet = playerFeet(); - if (playerFeet.equals(dest) && (BlockStateInterface.isLiquid(dest) || player().posY - playerFeet.getY() < 0.094)) { // lilypads + if (playerFeet.equals(dest) && (MovementHelper.isLiquid(dest) || player().posY - playerFeet.getY() < 0.094)) { // lilypads // Wait until we're actually on the ground before saying we're done because sometimes we continue to fall if the next action starts immediately return state.setStatus(MovementStatus.SUCCESS); /* else { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java index 19f72fca..8e5dd910 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java @@ -23,7 +23,6 @@ import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; -import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -57,16 +56,16 @@ public class MovementDiagonal extends Movement { } public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { - Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock(); + Block fromDown = context.get(x, y - 1, z).getBlock(); if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { return COST_INF; } - IBlockState destInto = BlockStateInterface.get(destX, y, destZ); - if (!MovementHelper.canWalkThrough(destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(destX, y + 1, destZ)) { + IBlockState destInto = context.get(destX, y, destZ); + if (!MovementHelper.canWalkThrough(context, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context, destX, y + 1, destZ)) { return COST_INF; } - IBlockState destWalkOn = BlockStateInterface.get(destX, y - 1, destZ); - if (!MovementHelper.canWalkOn(destX, y - 1, destZ, destWalkOn)) { + IBlockState destWalkOn = context.get(destX, y - 1, destZ); + if (!MovementHelper.canWalkOn(context, destX, y - 1, destZ, destWalkOn)) { return COST_INF; } double multiplier = WALK_ONE_BLOCK_COST; @@ -77,16 +76,16 @@ public class MovementDiagonal extends Movement { if (fromDown == Blocks.SOUL_SAND) { multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } - Block cuttingOver1 = BlockStateInterface.get(x, y - 1, destZ).getBlock(); - if (cuttingOver1 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver1)) { + Block cuttingOver1 = context.get(x, y - 1, destZ).getBlock(); + if (cuttingOver1 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver1)) { return COST_INF; } - Block cuttingOver2 = BlockStateInterface.get(destX, y - 1, z).getBlock(); - if (cuttingOver2 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver2)) { + Block cuttingOver2 = context.get(destX, y - 1, z).getBlock(); + if (cuttingOver2 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver2)) { return COST_INF; } - IBlockState pb0 = BlockStateInterface.get(x, y, destZ); - IBlockState pb2 = BlockStateInterface.get(destX, y, z); + IBlockState pb0 = context.get(x, y, destZ); + IBlockState pb2 = context.get(destX, y, z); double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false); double optionB = MovementHelper.getMiningDurationTicks(context, destX, y, z, pb2, false); if (optionA != 0 && optionB != 0) { @@ -94,13 +93,13 @@ public class MovementDiagonal extends Movement { // so no need to check pb1 as well, might as well return early here return COST_INF; } - IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ); + IBlockState pb1 = context.get(x, y + 1, destZ); optionA += MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true); if (optionA != 0 && optionB != 0) { // same deal, if pb1 makes optionA nonzero and option B already was nonzero, pb3 can't affect the result return COST_INF; } - IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z); + IBlockState pb3 = context.get(destX, y + 1, z); if (optionA == 0 && ((MovementHelper.avoidWalkingInto(pb2.getBlock()) && pb2.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb3.getBlock()) && pb3.getBlock() != Blocks.WATER))) { // at this point we're done calculating optionA, so we can check if it's actually possible to edge around in that direction return COST_INF; @@ -115,7 +114,7 @@ public class MovementDiagonal extends Movement { return COST_INF; } boolean water = false; - if (BlockStateInterface.isWater(BlockStateInterface.getBlock(x, y, z)) || BlockStateInterface.isWater(destInto.getBlock())) { + if (MovementHelper.isWater(context.getBlock(x, y, z)) || MovementHelper.isWater(destInto.getBlock())) { // Ignore previous multiplier // Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water // Not even touching the blocks below @@ -145,7 +144,7 @@ public class MovementDiagonal extends Movement { state.setStatus(MovementStatus.SUCCESS); return state; } - if (!BlockStateInterface.isLiquid(playerFeet())) { + if (!MovementHelper.isLiquid(playerFeet())) { state.setInput(InputOverrideHandler.Input.SPRINT, true); } MovementHelper.moveTowards(state, dest); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java index 0ac4f2b0..07c101e6 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java @@ -23,7 +23,6 @@ import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; -import baritone.utils.BlockStateInterface; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; @@ -48,10 +47,10 @@ public class MovementDownward extends Movement { } public static double cost(CalculationContext context, int x, int y, int z) { - if (!MovementHelper.canWalkOn(x, y - 2, z)) { + if (!MovementHelper.canWalkOn(context, x, y - 2, z)) { return COST_INF; } - IBlockState d = BlockStateInterface.get(x, y - 1, z); + IBlockState d = context.get(x, y - 1, z); Block td = d.getBlock(); boolean ladder = td == Blocks.LADDER || td == Blocks.VINE; if (ladder) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java index f7d63f17..ba57eeac 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java @@ -19,13 +19,15 @@ package baritone.pathing.movement.movements; import baritone.Baritone; import baritone.api.pathing.movement.MovementStatus; -import baritone.api.utils.*; +import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Rotation; +import baritone.api.utils.RotationUtils; +import baritone.api.utils.VecUtils; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState.MovementTarget; -import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.pathing.MutableMoveResult; import net.minecraft.entity.player.InventoryPlayer; @@ -63,18 +65,18 @@ public class MovementFall extends Movement { BlockPos playerFeet = playerFeet(); Rotation targetRotation = null; - if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) { + if (!MovementHelper.isWater(dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) { if (!InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_WATER)) || world().provider.isNether()) { return state.setStatus(MovementStatus.UNREACHABLE); } - if (player().posY - dest.getY() < mc.playerController.getBlockReachDistance()) { + if (player().posY - dest.getY() < playerController().getBlockReachDistance()) { player().inventory.currentItem = player().inventory.getSlotFor(STACK_BUCKET_WATER); targetRotation = new Rotation(player().rotationYaw, 90.0F); - RayTraceResult trace = RayTraceUtils.simulateRayTrace(player().rotationYaw, 90.0F); - if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK) { + RayTraceResult trace = mc.objectMouseOver; + if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && player().rotationPitch > 89.0F) { state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); } } @@ -84,8 +86,8 @@ public class MovementFall extends Movement { } else { state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.getBlockPosCenter(dest)), false)); } - if (playerFeet.equals(dest) && (player().posY - playerFeet.getY() < 0.094 || BlockStateInterface.isWater(dest))) { // 0.094 because lilypads - if (BlockStateInterface.isWater(dest)) { + if (playerFeet.equals(dest) && (player().posY - playerFeet.getY() < 0.094 || MovementHelper.isWater(dest))) { // 0.094 because lilypads + if (MovementHelper.isWater(dest)) { if (InventoryPlayer.isHotbar(player().inventory.getSlotFor(STACK_BUCKET_EMPTY))) { player().inventory.currentItem = player().inventory.getSlotFor(STACK_BUCKET_EMPTY); if (player().motionY >= 0) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 825c99f4..2b255d62 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -67,40 +67,50 @@ public class MovementParkour extends Movement { if (!Baritone.settings().allowParkour.get()) { return; } - IBlockState standingOn = BlockStateInterface.get(x, y - 1, z); + IBlockState standingOn = context.get(x, y - 1, z); if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) { return; } int xDiff = dir.getXOffset(); int zDiff = dir.getZOffset(); - IBlockState adj = BlockStateInterface.get(x + xDiff, y - 1, z + zDiff); + IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff); if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks return; } - if (MovementHelper.canWalkOn(x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) + if (MovementHelper.canWalkOn(context,x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) return; } - if (!MovementHelper.fullyPassable(x + xDiff, y, z + zDiff)) { + if (!MovementHelper.fullyPassable(context,x + xDiff, y, z + zDiff)) { return; } - if (!MovementHelper.fullyPassable(x + xDiff, y + 1, z + zDiff)) { + if (!MovementHelper.fullyPassable(context,x + xDiff, y + 1, z + zDiff)) { return; } - if (!MovementHelper.fullyPassable(x + xDiff, y + 2, z + zDiff)) { + if (!MovementHelper.fullyPassable(context,x + xDiff, y + 2, z + zDiff)) { return; } - if (!MovementHelper.fullyPassable(x, y + 2, z)) { + if (!MovementHelper.fullyPassable(context,x, y + 2, z)) { return; } - for (int i = 2; i <= (context.canSprint() ? 4 : 3); i++) { + int maxJump; + if (standingOn.getBlock() == Blocks.SOUL_SAND) { + maxJump = 2; // 1 block gap + } else { + if (context.canSprint()) { + maxJump = 4; + } else { + maxJump = 3; + } + } + for (int i = 2; i <= maxJump; i++) { // TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly? for (int y2 = 0; y2 < 4; y2++) { - if (!MovementHelper.fullyPassable(x + xDiff * i, y + y2, z + zDiff * i)) { + if (!MovementHelper.fullyPassable(context,x + xDiff * i, y + y2, z + zDiff * i)) { return; } } - if (MovementHelper.canWalkOn(x + xDiff * i, y - 1, z + zDiff * i)) { + if (MovementHelper.canWalkOn(context,x + xDiff * i, y - 1, z + zDiff * i)) { res.x = x + xDiff * i; res.y = y; res.z = z + zDiff * i; @@ -108,7 +118,7 @@ public class MovementParkour extends Movement { return; } } - if (!context.canSprint()) { + if (maxJump != 4) { return; } if (!Baritone.settings().allowParkourPlace.get()) { @@ -120,11 +130,11 @@ public class MovementParkour extends Movement { } int destX = x + 4 * xDiff; int destZ = z + 4 * zDiff; - IBlockState toPlace = BlockStateInterface.get(destX, y - 1, destZ); + IBlockState toPlace = context.get(destX, y - 1, destZ); if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) { return; } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace)) { + if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace)) { return; } for (int i = 0; i < 5; i++) { @@ -133,7 +143,7 @@ public class MovementParkour extends Movement { if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast continue; } - if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) { + if (MovementHelper.canPlaceAgainst(context,againstX, y - 1, againstZ)) { res.x = destX; res.y = y; res.z = destZ; @@ -217,7 +227,7 @@ public class MovementParkour extends Movement { double faceY = (dest.getY() + against1.getY()) * 0.5D; double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D; Rotation place = RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()); - RayTraceResult res = RayTraceUtils.rayTraceTowards(place); + RayTraceResult res = RayTraceUtils.rayTraceTowards(player(), place, playerController().getBlockReachDistance()); if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(dest.down())) { state.setTarget(new MovementState.MovementTarget(place, true)); } @@ -251,4 +261,4 @@ public class MovementParkour extends Movement { } return state; } -} \ No newline at end of file +} diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index c11df54a..846e4018 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -30,7 +30,6 @@ import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import net.minecraft.block.*; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -47,9 +46,9 @@ public class MovementPillar extends Movement { } public static double cost(CalculationContext context, int x, int y, int z) { - Block fromDown = BlockStateInterface.get(x, y, z).getBlock(); + Block fromDown = context.get(x, y, z).getBlock(); boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine; - IBlockState fromDownDown = BlockStateInterface.get(x, y - 1, z); + IBlockState fromDownDown = context.get(x, y - 1, z); if (!ladder) { if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) { return COST_INF; @@ -58,18 +57,18 @@ public class MovementPillar extends Movement { return COST_INF; // can't pillar up from a bottom slab onto a non ladder } } - if (fromDown instanceof BlockVine && !hasAgainst(x, y, z)) { + if (fromDown instanceof BlockVine && !hasAgainst(context, x, y, z)) { return COST_INF; } - IBlockState toBreak = BlockStateInterface.get(x, y + 2, z); + IBlockState toBreak = context.get(x, y + 2, z); Block toBreakBlock = toBreak.getBlock(); if (toBreakBlock instanceof BlockFenceGate) { return COST_INF; } Block srcUp = null; - if (BlockStateInterface.isWater(toBreakBlock) && BlockStateInterface.isWater(fromDown)) { - srcUp = BlockStateInterface.get(x, y + 1, z).getBlock(); - if (BlockStateInterface.isWater(srcUp)) { + if (MovementHelper.isWater(toBreakBlock) && MovementHelper.isWater(fromDown)) { + srcUp = context.get(x, y + 1, z).getBlock(); + if (MovementHelper.isWater(srcUp)) { return LADDER_UP_ONE_COST; } } @@ -84,11 +83,11 @@ public class MovementPillar extends Movement { if (toBreakBlock instanceof BlockLadder || toBreakBlock instanceof BlockVine) { hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it } else { - IBlockState check = BlockStateInterface.get(x, y + 3, z); + IBlockState check = context.get(x, y + 3, z); if (check.getBlock() instanceof BlockFalling) { // see MovementAscend's identical check for breaking a falling block above our head if (srcUp == null) { - srcUp = BlockStateInterface.get(x, y + 1, z).getBlock(); + srcUp = context.get(x, y + 1, z).getBlock(); } if (!(toBreakBlock instanceof BlockFalling) || !(srcUp instanceof BlockFalling)) { return COST_INF; @@ -113,24 +112,24 @@ public class MovementPillar extends Movement { } } - public static boolean hasAgainst(int x, int y, int z) { - return BlockStateInterface.get(x + 1, y, z).isBlockNormalCube() || - BlockStateInterface.get(x - 1, y, z).isBlockNormalCube() || - BlockStateInterface.get(x, y, z + 1).isBlockNormalCube() || - BlockStateInterface.get(x, y, z - 1).isBlockNormalCube(); + public static boolean hasAgainst(CalculationContext context, int x, int y, int z) { + return context.get(x + 1, y, z).isBlockNormalCube() || + context.get(x - 1, y, z).isBlockNormalCube() || + context.get(x, y, z + 1).isBlockNormalCube() || + context.get(x, y, z - 1).isBlockNormalCube(); } - public static BlockPos getAgainst(BlockPos vine) { - if (BlockStateInterface.get(vine.north()).isBlockNormalCube()) { + public static BlockPos getAgainst(CalculationContext context, BetterBlockPos vine) { + if (context.get(vine.north()).isBlockNormalCube()) { return vine.north(); } - if (BlockStateInterface.get(vine.south()).isBlockNormalCube()) { + if (context.get(vine.south()).isBlockNormalCube()) { return vine.south(); } - if (BlockStateInterface.get(vine.east()).isBlockNormalCube()) { + if (context.get(vine.east()).isBlockNormalCube()) { return vine.east(); } - if (BlockStateInterface.get(vine.west()).isBlockNormalCube()) { + if (context.get(vine.west()).isBlockNormalCube()) { return vine.west(); } return null; @@ -144,7 +143,7 @@ public class MovementPillar extends Movement { } IBlockState fromDown = BlockStateInterface.get(src); - if (BlockStateInterface.isWater(fromDown.getBlock()) && BlockStateInterface.isWater(dest)) { + if (MovementHelper.isWater(fromDown.getBlock()) && MovementHelper.isWater(dest)) { // stay centered while swimming up a water column state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.getBlockPosCenter(dest)), false)); Vec3d destCenter = VecUtils.getBlockPosCenter(dest); @@ -158,16 +157,16 @@ public class MovementPillar extends Movement { } boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine; boolean vine = fromDown.getBlock() instanceof BlockVine; - Rotation rotation = RotationUtils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), + Rotation rotation = RotationUtils.calcRotationFromVec3d(player().getPositionEyes(1.0F), VecUtils.getBlockPosCenter(positionToPlace), - new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)); + new Rotation(player().rotationYaw, player().rotationPitch)); if (!ladder) { - state.setTarget(new MovementState.MovementTarget(new Rotation(mc.player.rotationYaw, rotation.getPitch()), true)); + state.setTarget(new MovementState.MovementTarget(new Rotation(player().rotationYaw, rotation.getPitch()), true)); } boolean blockIsThere = MovementHelper.canWalkOn(src) || ladder; if (ladder) { - BlockPos against = vine ? getAgainst(src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite()); + BlockPos against = vine ? getAgainst(new CalculationContext(), src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite()); if (against == null) { logDebug("Unable to climb vines"); return state.setStatus(MovementStatus.UNREACHABLE); @@ -176,7 +175,7 @@ public class MovementPillar extends Movement { if (playerFeet().equals(against.up()) || playerFeet().equals(dest)) { return state.setStatus(MovementStatus.SUCCESS); } - if (MovementHelper.isBottomSlab(src.down())) { + if (MovementHelper.isBottomSlab(BlockStateInterface.get(src.down()))) { state.setInput(InputOverrideHandler.Input.JUMP, true); } /* @@ -215,10 +214,10 @@ public class MovementPillar extends Movement { if (!blockIsThere) { Block fr = BlockStateInterface.get(src).getBlock(); - if (!(fr instanceof BlockAir || fr.isReplaceable(Minecraft.getMinecraft().world, src))) { + if (!(fr instanceof BlockAir || fr.isReplaceable(world(), src))) { state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true); blockIsThere = false; - } else if (Minecraft.getMinecraft().player.isSneaking()) { // 1 tick after we're able to place + } else if (player().isSneaking()) { // 1 tick after we're able to place state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); } } @@ -240,9 +239,9 @@ public class MovementPillar extends Movement { state.setInput(InputOverrideHandler.Input.SNEAK, true); } } - if (BlockStateInterface.isWater(dest.up())) { + if (MovementHelper.isWater(dest.up())) { return true; } return super.prepared(state); } -} \ No newline at end of file +} diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index 7f9c3902..a4f32855 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -59,14 +59,14 @@ public class MovementTraverse extends Movement { } public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { - IBlockState pb0 = BlockStateInterface.get(destX, y + 1, destZ); - IBlockState pb1 = BlockStateInterface.get(destX, y, destZ); - IBlockState destOn = BlockStateInterface.get(destX, y - 1, destZ); - Block srcDown = BlockStateInterface.getBlock(x, y - 1, z); - if (MovementHelper.canWalkOn(destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge + IBlockState pb0 = context.get(destX, y + 1, destZ); + IBlockState pb1 = context.get(destX, y, destZ); + IBlockState destOn = context.get(destX, y - 1, destZ); + Block srcDown = context.getBlock(x, y - 1, z); + if (MovementHelper.canWalkOn(context, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge double WC = WALK_ONE_BLOCK_COST; boolean water = false; - if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) { + if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) { WC = context.waterWalkSpeed(); water = true; } else { @@ -101,8 +101,8 @@ public class MovementTraverse extends Movement { return COST_INF; } if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(destX, y - 1, destZ, destOn)) { - boolean throughWater = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock()); - if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) { + boolean throughWater = MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock()); + if (MovementHelper.isWater(destOn.getBlock()) && throughWater) { return COST_INF; } if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) { @@ -121,7 +121,7 @@ public class MovementTraverse extends Movement { if (againstX == x && againstZ == z) { continue; } - if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) { + if (MovementHelper.canPlaceAgainst(context, againstX, y - 1, againstZ)) { return WC + context.placeBlockCost() + hardness1 + hardness2; } } @@ -223,7 +223,7 @@ public class MovementTraverse extends Movement { if (playerFeet().equals(dest)) { return state.setStatus(MovementStatus.SUCCESS); } - if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) { + if (wasTheBridgeBlockAlwaysThere && !MovementHelper.isLiquid(playerFeet())) { state.setInput(InputOverrideHandler.Input.SPRINT, true); } Block destDown = BlockStateInterface.get(dest.down()).getBlock(); @@ -265,7 +265,7 @@ public class MovementTraverse extends Movement { state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true)); EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit; - if (Objects.equals(RayTraceUtils.getSelectedBlock().orElse(null), against1) && (Minecraft.getMinecraft().player.isSneaking() || Baritone.settings().assumeSafeWalk.get()) && RayTraceUtils.getSelectedBlock().get().offset(side).equals(positionToPlace)) { + if (Objects.equals(RayTraceUtils.getSelectedBlock().orElse(null), against1) && (player().isSneaking() || Baritone.settings().assumeSafeWalk.get()) && RayTraceUtils.getSelectedBlock().get().offset(side).equals(positionToPlace)) { return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); } //System.out.println("Trying to look at " + against1 + ", actually looking at" + RayTraceUtils.getSelectedBlock()); diff --git a/src/main/java/baritone/pathing/calc/CutoffPath.java b/src/main/java/baritone/pathing/path/CutoffPath.java similarity index 74% rename from src/main/java/baritone/pathing/calc/CutoffPath.java rename to src/main/java/baritone/pathing/path/CutoffPath.java index 53e0c560..30b2d4e9 100644 --- a/src/main/java/baritone/pathing/calc/CutoffPath.java +++ b/src/main/java/baritone/pathing/path/CutoffPath.java @@ -15,17 +15,18 @@ * along with Baritone. If not, see . */ -package baritone.pathing.calc; +package baritone.pathing.path; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import baritone.utils.pathing.PathBase; import java.util.Collections; import java.util.List; -public class CutoffPath implements IPath { +public class CutoffPath extends PathBase { private final List path; @@ -35,11 +36,16 @@ public class CutoffPath implements IPath { private final Goal goal; - CutoffPath(IPath prev, int lastPositionToInclude) { - path = prev.positions().subList(0, lastPositionToInclude + 1); - movements = prev.movements().subList(0, lastPositionToInclude + 1); + public CutoffPath(IPath prev, int firstPositionToInclude, int lastPositionToInclude) { + path = prev.positions().subList(firstPositionToInclude, lastPositionToInclude + 1); + movements = prev.movements().subList(firstPositionToInclude, lastPositionToInclude); numNodes = prev.getNumNodesConsidered(); goal = prev.getGoal(); + sanityCheck(); + } + + public CutoffPath(IPath prev, int lastPositionToInclude) { + this(prev, 0, lastPositionToInclude); } @Override diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index e5f9c864..5cc472e6 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -454,6 +454,43 @@ public class PathExecutor implements IPathExecutor, Helper { return pathPosition; } + public PathExecutor trySplice(PathExecutor next) { + if (next == null) { + return cutIfTooLong(); + } + return SplicedPath.trySplice(path, next.path).map(path -> { + if (!path.getDest().equals(next.getPath().getDest())) { + throw new IllegalStateException(); + } + PathExecutor ret = new PathExecutor(path); + ret.pathPosition = pathPosition; + ret.currentMovementOriginalCostEstimate = currentMovementOriginalCostEstimate; + ret.costEstimateIndex = costEstimateIndex; + ret.ticksOnCurrent = ticksOnCurrent; + return ret; + }).orElse(cutIfTooLong()); + } + + private PathExecutor cutIfTooLong() { + if (pathPosition > Baritone.settings().maxPathHistoryLength.get()) { + int cutoffAmt = Baritone.settings().pathHistoryCutoffAmount.get(); + CutoffPath newPath = new CutoffPath(path, cutoffAmt, path.length() - 1); + if (!newPath.getDest().equals(path.getDest())) { + throw new IllegalStateException(); + } + logDebug("Discarding earliest segment movements, length cut from " + path.length() + " to " + newPath.length()); + PathExecutor ret = new PathExecutor(newPath); + ret.pathPosition = pathPosition - cutoffAmt; + ret.currentMovementOriginalCostEstimate = currentMovementOriginalCostEstimate; + if (costEstimateIndex != null) { + ret.costEstimateIndex = costEstimateIndex - cutoffAmt; + } + ret.ticksOnCurrent = ticksOnCurrent; + return ret; + } + return this; + } + @Override public IPath getPath() { return path; diff --git a/src/main/java/baritone/pathing/path/SplicedPath.java b/src/main/java/baritone/pathing/path/SplicedPath.java new file mode 100644 index 00000000..5048a84a --- /dev/null +++ b/src/main/java/baritone/pathing/path/SplicedPath.java @@ -0,0 +1,89 @@ +/* + * 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 . + */ + +package baritone.pathing.path; + +import baritone.api.pathing.calc.IPath; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.movement.IMovement; +import baritone.api.utils.BetterBlockPos; +import baritone.utils.pathing.PathBase; + +import java.util.*; + +public class SplicedPath extends PathBase { + private final List path; + + private final List movements; + + private final int numNodes; + + private final Goal goal; + + private SplicedPath(List path, List movements, int numNodesConsidered, Goal goal) { + this.path = path; + this.movements = movements; + this.numNodes = numNodesConsidered; + this.goal = goal; + sanityCheck(); + } + + @Override + public Goal getGoal() { + return goal; + } + + @Override + public List movements() { + return Collections.unmodifiableList(movements); + } + + @Override + public List positions() { + return Collections.unmodifiableList(path); + } + + @Override + public int getNumNodesConsidered() { + return numNodes; + } + + public static Optional trySplice(IPath first, IPath second) { + if (second == null || first == null) { + return Optional.empty(); + } + if (!Objects.equals(first.getGoal(), second.getGoal())) { + return Optional.empty(); + } + if (!first.getDest().equals(second.getSrc())) { + return Optional.empty(); + } + HashSet a = new HashSet<>(first.positions()); + for (int i = 1; i < second.length(); i++) { + if (a.contains(second.positions().get(i))) { + return Optional.empty(); + } + } + List positions = new ArrayList<>(); + List movements = new ArrayList<>(); + positions.addAll(first.positions()); + positions.addAll(second.positions().subList(1, second.length())); + movements.addAll(first.movements()); + movements.addAll(second.movements()); + return Optional.of(new SplicedPath(positions, movements, first.getNumNodesConsidered() + second.getNumNodesConsidered(), first.getGoal())); + } +} diff --git a/src/main/java/baritone/process/CustomGoalProcess.java b/src/main/java/baritone/process/CustomGoalProcess.java new file mode 100644 index 00000000..98c700e3 --- /dev/null +++ b/src/main/java/baritone/process/CustomGoalProcess.java @@ -0,0 +1,115 @@ +/* + * 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 . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.pathing.goals.Goal; +import baritone.api.process.ICustomGoalProcess; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.utils.BaritoneProcessHelper; + +import java.util.Objects; + +/** + * As set by ExampleBaritoneControl or something idk + * + * @author leijurv + */ +public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomGoalProcess { + + /** + * The current goal + */ + private Goal goal; + + /** + * The current process state. + * + * @see State + */ + private State state; + + public CustomGoalProcess(Baritone baritone) { + super(baritone, 3); + } + + @Override + public void setGoal(Goal goal) { + this.goal = goal; + this.state = State.GOAL_SET; + } + + @Override + public void path() { + this.state = State.PATH_REQUESTED; + } + + @Override + public Goal getGoal() { + return this.goal; + } + + @Override + public boolean isActive() { + return this.state != State.NONE; + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + switch (this.state) { + case GOAL_SET: + if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal(), this.goal)) { + this.state = State.NONE; + } + return new PathingCommand(this.goal, PathingCommandType.CANCEL_AND_SET_GOAL); + case PATH_REQUESTED: + PathingCommand ret = new PathingCommand(this.goal, PathingCommandType.SET_GOAL_AND_PATH); + this.state = State.EXECUTING; + return ret; + case EXECUTING: + if (calcFailed) { + onLostControl(); + } + if (this.goal == null || this.goal.isInGoal(playerFeet())) { + onLostControl(); // we're there xd + } + return new PathingCommand(this.goal, PathingCommandType.SET_GOAL_AND_PATH); + default: + throw new IllegalStateException(); + } + } + + @Override + public void onLostControl() { + this.state = State.NONE; + this.goal = null; + } + + @Override + public String displayName() { + return "Custom Goal " + this.goal; + } + + protected enum State { + NONE, + GOAL_SET, + PATH_REQUESTED, + EXECUTING + } +} diff --git a/src/main/java/baritone/process/FollowProcess.java b/src/main/java/baritone/process/FollowProcess.java new file mode 100644 index 00000000..41a59808 --- /dev/null +++ b/src/main/java/baritone/process/FollowProcess.java @@ -0,0 +1,126 @@ +/* + * 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 . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.pathing.goals.GoalNear; +import baritone.api.pathing.goals.GoalXZ; +import baritone.api.process.IFollowProcess; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.utils.BaritoneProcessHelper; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Follow an entity + * + * @author leijurv + */ +public final class FollowProcess extends BaritoneProcessHelper implements IFollowProcess { + + private Predicate filter; + private List cache; + + public FollowProcess(Baritone baritone) { + super(baritone, 1); + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + scanWorld(); + Goal goal = new GoalComposite(cache.stream().map(this::towards).toArray(Goal[]::new)); + return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); + } + + private Goal towards(Entity following) { + // lol this is trashy but it works + BlockPos pos; + if (Baritone.settings().followOffsetDistance.get() == 0) { + pos = new BlockPos(following); + } else { + GoalXZ g = GoalXZ.fromDirection(following.getPositionVector(), Baritone.settings().followOffsetDirection.get(), Baritone.settings().followOffsetDistance.get()); + pos = new BlockPos(g.getX(), following.posY, g.getZ()); + } + return new GoalNear(pos, Baritone.settings().followRadius.get()); + } + + + private boolean followable(Entity entity) { + if (entity == null) { + return false; + } + if (entity.isDead) { + return false; + } + if (entity.equals(player())) { + return false; + } + if (!world().loadedEntityList.contains(entity) && !world().playerEntities.contains(entity)) { + return false; + } + return true; + } + + private void scanWorld() { + cache = Stream.of(world().loadedEntityList, world().playerEntities).flatMap(List::stream).filter(this::followable).filter(this.filter).distinct().collect(Collectors.toCollection(ArrayList::new)); + } + + @Override + public boolean isActive() { + if (filter == null) { + return false; + } + scanWorld(); + return !cache.isEmpty(); + } + + @Override + public void onLostControl() { + filter = null; + cache = null; + } + + @Override + public String displayName() { + return "Follow " + cache; + } + + @Override + public void follow(Predicate filter) { + this.filter = filter; + } + + @Override + public List following() { + return cache; + } + + @Override + public Predicate currentFilter() { + return filter; + } +} diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java new file mode 100644 index 00000000..0fb2abc0 --- /dev/null +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -0,0 +1,102 @@ +/* + * 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 . + */ + +package baritone.process; + +import baritone.Baritone; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.pathing.goals.GoalGetToBlock; +import baritone.api.process.IGetToBlockProcess; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; +import baritone.utils.BaritoneProcessHelper; +import net.minecraft.block.Block; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess { + private Block gettingTo; + private List knownLocations; + + private int tickCount = 0; + + public GetToBlockProcess(Baritone baritone) { + super(baritone, 2); + } + + @Override + public void getToBlock(Block block) { + gettingTo = block; + knownLocations = null; + rescan(new ArrayList<>()); + } + + @Override + public boolean isActive() { + return gettingTo != null; + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + if (knownLocations == null) { + rescan(new ArrayList<>()); + } + if (knownLocations.isEmpty()) { + logDirect("No known locations of " + gettingTo + ", canceling GetToBlock"); + if (isSafeToCancel) { + onLostControl(); + } + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); + } + if (calcFailed) { + logDirect("Unable to find any path to " + gettingTo + ", canceling GetToBlock"); + if (isSafeToCancel) { + onLostControl(); + } + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); + } + int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); + if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain + List current = new ArrayList<>(knownLocations); + Baritone.getExecutor().execute(() -> rescan(current)); + } + Goal goal = new GoalComposite(knownLocations.stream().map(GoalGetToBlock::new).toArray(Goal[]::new)); + if (goal.isInGoal(playerFeet())) { + onLostControl(); + } + return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); + } + + @Override + public void onLostControl() { + gettingTo = null; + knownLocations = null; + } + + @Override + public String displayName() { + return "Get To Block " + gettingTo; + } + + private void rescan(List known) { + knownLocations = MineProcess.searchWorld(Collections.singletonList(gettingTo), 64, baritone.getWorldProvider(), world(), known); + } +} \ No newline at end of file diff --git a/src/main/java/baritone/behavior/MineBehavior.java b/src/main/java/baritone/process/MineProcess.java similarity index 56% rename from src/main/java/baritone/behavior/MineBehavior.java rename to src/main/java/baritone/process/MineProcess.java index d76f0dc1..c3a61426 100644 --- a/src/main/java/baritone/behavior/MineBehavior.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -15,25 +15,31 @@ * along with Baritone. If not, see . */ -package baritone.behavior; +package baritone.process; import baritone.Baritone; -import baritone.api.behavior.IMineBehavior; -import baritone.api.event.events.TickEvent; import baritone.api.pathing.goals.*; +import baritone.api.process.IMineProcess; +import baritone.api.process.PathingCommand; +import baritone.api.process.PathingCommandType; import baritone.api.utils.RotationUtils; import baritone.cache.CachedChunk; import baritone.cache.ChunkPacker; import baritone.cache.WorldProvider; import baritone.cache.WorldScanner; +import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; +import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.chunk.EmptyChunk; import java.util.*; @@ -44,26 +50,28 @@ import java.util.stream.Collectors; * * @author leijurv */ -public final class MineBehavior extends Behavior implements IMineBehavior, Helper { +public final class MineProcess extends BaritoneProcessHelper implements IMineProcess { + + private static final int ORE_LOCATIONS_COUNT = 64; private List mining; private List knownOreLocations; private BlockPos branchPoint; + private GoalRunAway branchPointRunaway; private int desiredQuantity; + private int tickCount; - public MineBehavior(Baritone baritone) { - super(baritone); + public MineProcess(Baritone baritone) { + super(baritone, 0); } @Override - public void onTick(TickEvent event) { - if (event.getType() == TickEvent.Type.OUT) { - cancel(); - return; - } - if (mining == null) { - return; - } + public boolean isActive() { + return mining != null; + } + + @Override + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (desiredQuantity > 0) { Item item = mining.get(0).getItemDropped(mining.get(0).getDefaultState(), new Random(), 0); int curr = player().inventory.mainInventory.stream().filter(stack -> item.equals(stack.getItem())).mapToInt(ItemStack::getCount).sum(); @@ -71,66 +79,92 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe if (curr >= desiredQuantity) { logDirect("Have " + curr + " " + item.getItemStackDisplayName(new ItemStack(item, 1))); cancel(); - return; + return null; } } + if (calcFailed) { + logDirect("Unable to find any path to " + mining + ", canceling Mine"); + cancel(); + return null; + } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); - if (mineGoalUpdateInterval != 0 && event.getCount() % mineGoalUpdateInterval == 0) { - Baritone.INSTANCE.getExecutor().execute(this::rescan); + if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain + List curr = new ArrayList<>(knownOreLocations); + baritone.getExecutor().execute(() -> rescan(curr)); } if (Baritone.settings().legitMine.get()) { addNearby(); } - updateGoal(); - baritone.getPathingBehavior().revalidateGoal(); + Goal goal = updateGoal(); + if (goal == null) { + // none in range + // maybe say something in chat? (ahem impact) + cancel(); + return null; + } + return new PathingCommand(goal, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH); } - private void updateGoal() { - if (mining == null) { - return; - } + @Override + public void onLostControl() { + mine(0, (Block[]) null); + } + + @Override + public String displayName() { + return "Mine " + mining; + } + + private Goal updateGoal() { List locs = knownOreLocations; if (!locs.isEmpty()) { - List locs2 = prune(new ArrayList<>(locs), mining, 64); + List locs2 = prune(new ArrayList<>(locs), mining, ORE_LOCATIONS_COUNT, world()); // can't reassign locs, gotta make a new var locs2, because we use it in a lambda right here, and variables you use in a lambda must be effectively final - baritone.getPathingBehavior().setGoalAndPath(new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2)).toArray(Goal[]::new))); - knownOreLocations = locs; - return; + Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2)).toArray(Goal[]::new)); + knownOreLocations = locs2; + return goal; } // we don't know any ore locations at the moment if (!Baritone.settings().legitMine.get()) { - return; + return null; } // only in non-Xray mode (aka legit mode) do we do this + int y = Baritone.settings().legitMineYLevel.get(); if (branchPoint == null) { - int y = Baritone.settings().legitMineYLevel.get(); - if (!baritone.getPathingBehavior().isPathing() && playerFeet().y == y) { + /*if (!baritone.getPathingBehavior().isPathing() && playerFeet().y == y) { // cool, path is over and we are at desired y branchPoint = playerFeet(); + branchPointRunaway = null; } else { - baritone.getPathingBehavior().setGoalAndPath(new GoalYLevel(y)); - return; - } + return new GoalYLevel(y); + }*/ + branchPoint = playerFeet(); } - - if (playerFeet().equals(branchPoint)) { - // TODO mine 1x1 shafts to either side - branchPoint = branchPoint.north(10); + // TODO shaft mode, mine 1x1 shafts to either side + // TODO also, see if the GoalRunAway with maintain Y at 11 works even from the surface + if (branchPointRunaway == null) { + branchPointRunaway = new GoalRunAway(1, Optional.of(y), branchPoint) { + @Override + public boolean isInGoal(int x, int y, int z) { + return false; + } + }; } - baritone.getPathingBehavior().setGoalAndPath(new GoalBlock(branchPoint)); + return branchPointRunaway; } - private void rescan() { + private void rescan(List already) { if (mining == null) { return; } if (Baritone.settings().legitMine.get()) { return; } - List locs = searchWorld(mining, 64); + List locs = searchWorld(mining, ORE_LOCATIONS_COUNT, baritone.getWorldProvider(), world(), already); + locs.addAll(droppedItemsScan(mining, world())); if (locs.isEmpty()) { logDebug("No locations for " + mining + " known, cancelling"); - mine(0, (String[]) null); + cancel(); return; } knownOreLocations = locs; @@ -158,13 +192,39 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe } } - public List searchWorld(List mining, int max) { + public static List droppedItemsScan(List mining, World world) { + if (!Baritone.settings().mineScanDroppedItems.get()) { + return new ArrayList<>(); + } + Set searchingFor = new HashSet<>(); + for (Block block : mining) { + Item drop = block.getItemDropped(block.getDefaultState(), new Random(), 0); + Item ore = Item.getItemFromBlock(block); + searchingFor.add(drop); + searchingFor.add(ore); + } + List ret = new ArrayList<>(); + for (Entity entity : world.loadedEntityList) { + if (entity instanceof EntityItem) { + EntityItem ei = (EntityItem) entity; + if (searchingFor.contains(ei.getItem().getItem())) { + ret.add(new BlockPos(entity)); + } + } + } + return ret; + } + + /*public static List searchWorld(List mining, int max, World world) { + + }*/ + public static List searchWorld(List mining, int max, WorldProvider provider, World world, List alreadyKnown) { List locs = new ArrayList<>(); List uninteresting = new ArrayList<>(); //long b = System.currentTimeMillis(); for (Block m : mining) { if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(m)) { - locs.addAll(WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), 1, 1)); + locs.addAll(provider.getCurrentWorld().getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), 1, 1)); } else { uninteresting.add(m); } @@ -178,34 +238,38 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(uninteresting, max, 10, 26)); //System.out.println("Scan of loaded chunks took " + (System.currentTimeMillis() - before) + "ms"); } - return prune(locs, mining, max); + locs.addAll(alreadyKnown); + return prune(locs, mining, max, world); } public void addNearby() { + knownOreLocations.addAll(droppedItemsScan(mining, world())); BlockPos playerFeet = playerFeet(); int searchDist = 4;//why four? idk for (int x = playerFeet.getX() - searchDist; x <= playerFeet.getX() + searchDist; x++) { for (int y = playerFeet.getY() - searchDist; y <= playerFeet.getY() + searchDist; y++) { for (int z = playerFeet.getZ() - searchDist; z <= playerFeet.getZ() + searchDist; z++) { BlockPos pos = new BlockPos(x, y, z); - if (mining.contains(BlockStateInterface.getBlock(pos)) && RotationUtils.reachable(player(), pos).isPresent()) {//crucial to only add blocks we can see because otherwise this is an x-ray and it'll get caught + if (mining.contains(BlockStateInterface.getBlock(pos)) && RotationUtils.reachable(player(), pos, playerController().getBlockReachDistance()).isPresent()) {//crucial to only add blocks we can see because otherwise this is an x-ray and it'll get caught knownOreLocations.add(pos); } } } } - knownOreLocations = prune(knownOreLocations, mining, 64); + knownOreLocations = prune(knownOreLocations, mining, ORE_LOCATIONS_COUNT, world()); } - public List prune(List locs2, List mining, int max) { + public static List prune(List locs2, List mining, int max, World world) { + List dropped = droppedItemsScan(mining, world); List locs = locs2 .stream() + .distinct() // remove any that are within loaded chunks that aren't actually what we want - .filter(pos -> world().getChunk(pos) instanceof EmptyChunk || mining.contains(BlockStateInterface.get(pos).getBlock())) + .filter(pos -> world.getChunk(pos) instanceof EmptyChunk || mining.contains(BlockStateInterface.get(pos).getBlock()) || dropped.contains(pos)) // remove any that are implausible to mine (encased in bedrock, or touching lava) - .filter(MineBehavior::plausibleToBreak) + .filter(MineProcess::plausibleToBreak) .sorted(Comparator.comparingDouble(Helper.HELPER.playerFeet()::distanceSq)) .collect(Collectors.toList()); @@ -217,7 +281,7 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe } public static boolean plausibleToBreak(BlockPos pos) { - if (MovementHelper.avoidBreaking(pos.getX(), pos.getY(), pos.getZ(), BlockStateInterface.get(pos))) { + if (MovementHelper.avoidBreaking(new CalculationContext(), pos.getX(), pos.getY(), pos.getZ(), BlockStateInterface.get(pos))) { return false; } // bedrock above and below makes it implausible, otherwise we're good @@ -225,13 +289,8 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe } @Override - public void mine(int quantity, String... blocks) { - this.mining = blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(ChunkPacker::stringToBlock).collect(Collectors.toList()); - this.desiredQuantity = quantity; - this.knownOreLocations = new ArrayList<>(); - this.branchPoint = null; - rescan(); - updateGoal(); + public void mineByName(int quantity, String... blocks) { + mine(quantity, blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(ChunkPacker::stringToBlock).toArray(Block[]::new)); } @Override @@ -240,13 +299,7 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe this.desiredQuantity = quantity; this.knownOreLocations = new ArrayList<>(); this.branchPoint = null; - rescan(); - updateGoal(); - } - - @Override - public void cancel() { - mine(0, (String[]) null); - baritone.getPathingBehavior().cancel(); + this.branchPointRunaway = null; + rescan(new ArrayList<>()); } } diff --git a/src/main/java/baritone/utils/BaritoneAutoTest.java b/src/main/java/baritone/utils/BaritoneAutoTest.java index 70e1a70e..4aee4bd4 100644 --- a/src/main/java/baritone/utils/BaritoneAutoTest.java +++ b/src/main/java/baritone/utils/BaritoneAutoTest.java @@ -105,8 +105,7 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper { } // Setup Baritone's pathing goal and (if needed) begin pathing - Baritone.INSTANCE.getPathingBehavior().setGoal(GOAL); - Baritone.INSTANCE.getPathingBehavior().path(); + Baritone.INSTANCE.getCustomGoalProcess().setGoalAndPath(GOAL); // If we have reached our goal, print a message and safely close the game if (GOAL.isInGoal(playerFeet())) { diff --git a/src/main/java/baritone/utils/BaritoneProcessHelper.java b/src/main/java/baritone/utils/BaritoneProcessHelper.java new file mode 100644 index 00000000..d01e815d --- /dev/null +++ b/src/main/java/baritone/utils/BaritoneProcessHelper.java @@ -0,0 +1,53 @@ +/* + * 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 . + */ + +package baritone.utils; + +import baritone.Baritone; +import baritone.api.process.IBaritoneProcess; + +public abstract class BaritoneProcessHelper implements IBaritoneProcess, Helper { + public static final double DEFAULT_PRIORITY = 0; + + protected final Baritone baritone; + private final double priority; + + public BaritoneProcessHelper(Baritone baritone) { + this(baritone, DEFAULT_PRIORITY); + } + + public BaritoneProcessHelper(Baritone baritone, double priority) { + this.baritone = baritone; + this.priority = priority; + baritone.getPathingControlManager().registerProcess(this); + } + + @Override + public Baritone associatedWith() { + return baritone; + } + + @Override + public boolean isTemporary() { + return false; + } + + @Override + public double priority() { + return priority; + } +} diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java index 1bc4a44a..b1e9ae53 100644 --- a/src/main/java/baritone/utils/BlockBreakHelper.java +++ b/src/main/java/baritone/utils/BlockBreakHelper.java @@ -20,6 +20,7 @@ package baritone.utils; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; /** * @author Brady @@ -32,6 +33,7 @@ public final class BlockBreakHelper implements Helper { * between attempts, then we re-initialize the breaking process. */ private static BlockPos lastBlock; + private static boolean didBreakLastTick; private BlockBreakHelper() {} @@ -48,7 +50,23 @@ public final class BlockBreakHelper implements Helper { public static void stopBreakingBlock() { if (mc.playerController != null) { mc.playerController.resetBlockRemoving(); - } + } lastBlock = null; } + + public static boolean tick(boolean isLeftClick) { + RayTraceResult trace = mc.objectMouseOver; + boolean isBlockTrace = trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK; + + // If we're forcing left click, we're in a gui screen, and we're looking + // at a block, break the block without a direct game input manipulation. + if (mc.currentScreen != null && isLeftClick && isBlockTrace) { + tryBreakBlock(trace.getBlockPos(), trace.sideHit); + didBreakLastTick = true; + } else if (didBreakLastTick) { + stopBreakingBlock(); + didBreakLastTick = false; + } + return !didBreakLastTick && isLeftClick; + } } diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index 2c0384b2..547e40c3 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -20,12 +20,12 @@ package baritone.utils; import baritone.Baritone; import baritone.cache.CachedRegion; import baritone.cache.WorldData; -import baritone.cache.WorldProvider; +import baritone.pathing.movement.CalculationContext; import net.minecraft.block.Block; -import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; /** @@ -35,16 +35,31 @@ import net.minecraft.world.chunk.Chunk; */ public class BlockStateInterface implements Helper { - private static Chunk prev = null; - private static CachedRegion prevCached = null; + private final World world; + private final WorldData worldData; + + + private Chunk prev = null; + private CachedRegion prevCached = null; private static final IBlockState AIR = Blocks.AIR.getDefaultState(); - public static IBlockState get(BlockPos pos) { - return get(pos.getX(), pos.getY(), pos.getZ()); + public BlockStateInterface(World world, WorldData worldData) { + this.worldData = worldData; + this.world = world; } - public static IBlockState get(int x, int y, int z) { + public static Block getBlock(BlockPos pos) { // won't be called from the pathing thread because the pathing thread doesn't make a single blockpos pog + return get(pos).getBlock(); + } + + public static IBlockState get(BlockPos pos) { + return new CalculationContext().get(pos); // immense iq + // can't just do world().get because that doesn't work for out of bounds + // and toBreak and stuff fails when the movement is instantiated out of load range but it's not able to BlockStateInterface.get what it's going to walk on + } + + public IBlockState get0(int x, int y, int z) { // Invalid vertical position if (y < 0 || y >= 256) { @@ -62,7 +77,7 @@ public class BlockStateInterface implements Helper { if (cached != null && cached.x == x >> 4 && cached.z == z >> 4) { return cached.getBlockState(x, y, z); } - Chunk chunk = mc.world.getChunk(x >> 4, z >> 4); + Chunk chunk = world.getChunk(x >> 4, z >> 4); if (chunk.isLoaded()) { prev = chunk; return chunk.getBlockState(x, y, z); @@ -72,11 +87,10 @@ public class BlockStateInterface implements Helper { // except here, it's 512x512 tiles instead of 16x16, so even better repetition CachedRegion cached = prevCached; if (cached == null || cached.getX() != x >> 9 || cached.getZ() != z >> 9) { - WorldData world = WorldProvider.INSTANCE.getCurrentWorld(); - if (world == null) { + if (worldData == null) { return AIR; } - CachedRegion region = world.cache.getRegion(x >> 9, z >> 9); + CachedRegion region = worldData.cache.getRegion(x >> 9, z >> 9); if (region == null) { return AIR; } @@ -90,12 +104,12 @@ public class BlockStateInterface implements Helper { return type; } - public static boolean isLoaded(int x, int z) { + public boolean isLoaded(int x, int z) { Chunk prevChunk = prev; if (prevChunk != null && prevChunk.x == x >> 4 && prevChunk.z == z >> 4) { return true; } - prevChunk = mc.world.getChunk(x >> 4, z >> 4); + prevChunk = world.getChunk(x >> 4, z >> 4); if (prevChunk.isLoaded()) { prev = prevChunk; return true; @@ -104,71 +118,14 @@ public class BlockStateInterface implements Helper { if (prevRegion != null && prevRegion.getX() == x >> 9 && prevRegion.getZ() == z >> 9) { return prevRegion.isCached(x & 511, z & 511); } - WorldData world = WorldProvider.INSTANCE.getCurrentWorld(); - if (world == null) { + if (worldData == null) { return false; } - prevRegion = world.cache.getRegion(x >> 9, z >> 9); + prevRegion = worldData.cache.getRegion(x >> 9, z >> 9); if (prevRegion == null) { return false; } prevCached = prevRegion; return prevRegion.isCached(x & 511, z & 511); } - - public static void clearCachedChunk() { - prev = null; - prevCached = null; - } - - public static Block getBlock(BlockPos pos) { - return get(pos).getBlock(); - } - - public static Block getBlock(int x, int y, int z) { - return get(x, y, z).getBlock(); - } - - /** - * Returns whether or not the specified block is - * water, regardless of whether or not it is flowing. - * - * @param b The block - * @return Whether or not the block is water - */ - public static boolean isWater(Block b) { - return b == Blocks.FLOWING_WATER || b == Blocks.WATER; - } - - /** - * Returns whether or not the block at the specified pos is - * water, regardless of whether or not it is flowing. - * - * @param bp The block pos - * @return Whether or not the block is water - */ - public static boolean isWater(BlockPos bp) { - return isWater(BlockStateInterface.getBlock(bp)); - } - - public static boolean isLava(Block b) { - return b == Blocks.FLOWING_LAVA || b == Blocks.LAVA; - } - - /** - * Returns whether or not the specified pos has a liquid - * - * @param p The pos - * @return Whether or not the block is a liquid - */ - public static boolean isLiquid(BlockPos p) { - return BlockStateInterface.getBlock(p) instanceof BlockLiquid; - } - - public static boolean isFlowing(IBlockState state) { - // Will be IFluidState in 1.13 - return state.getBlock() instanceof BlockLiquid - && state.getPropertyKeys().contains(BlockLiquid.LEVEL) - && state.getValue(BlockLiquid.LEVEL) != 0; - } } diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index 02c48885..2f6bef6c 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -29,10 +29,11 @@ import baritone.behavior.Behavior; import baritone.behavior.PathingBehavior; import baritone.cache.ChunkPacker; import baritone.cache.Waypoint; -import baritone.cache.WorldProvider; import baritone.pathing.calc.AbstractNodeCostSearch; +import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; +import baritone.process.CustomGoalProcess; import net.minecraft.block.Block; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.entity.Entity; @@ -46,6 +47,35 @@ import java.util.stream.Stream; public class ExampleBaritoneControl extends Behavior implements Helper { + private static final String HELP_MSG = + "baritone - Output settings into chat\n" + + "settings - Same as baritone\n" + + "goal - Create a goal (one number is '', two is ' ', three is ' , 'clear' to clear)\n" + + "path - Go towards goal\n" + + "repack - (debug) Repacks chunk cache\n" + + "rescan - (debug) Same as repack\n" + + "axis - Paths towards the closest axis or diagonal axis, at y=120\n" + + "cancel - Cancels current path\n" + + "forcecancel - sudo cancel (only use if very glitched, try toggling 'pause' first)\n" + + "gc - Calls System.gc();\n" + + "invert - Runs away from the goal instead of towards it\n" + + "follow - Follows a player 'follow username'\n" + + "reloadall - (debug) Reloads chunk cache\n" + + "saveall - (debug) Saves chunk cache\n" + + "find - (debug) outputs how many blocks of a certain type are within the cache\n" + + "mine - Paths to and mines specified blocks 'mine x_ore y_ore ...'\n" + + "thisway - Creates a goal X blocks where you're facing\n" + + "list - Lists waypoints under a category\n" + + "get - Same as list\n" + + "show - Same as list\n" + + "save - Saves a waypoint (works but don't try to make sense of it)\n" + + "goto - Paths towards specified block or waypoint\n" + + "spawn - Paths towards world spawn or your most recent bed right-click\n" + + "sethome - Sets \"home\"\n" + + "home - Paths towards \"home\" \n" + + "costs - (debug) all movement costs from current location\n" + + "damn - Daniel "; + public ExampleBaritoneControl(Baritone baritone) { super(baritone); } @@ -70,6 +100,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { public boolean runCommand(String msg0) { String msg = msg0.toLowerCase(Locale.US).trim(); // don't reassign the argument LOL PathingBehavior pathingBehavior = baritone.getPathingBehavior(); + CustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess(); List> toggleable = Baritone.settings().getAllValuesByType(Boolean.class); for (Settings.Setting setting : toggleable) { if (msg.equalsIgnoreCase(setting.getName())) { @@ -85,6 +116,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } return true; } + if (msg.equals("") || msg.equals("help") || msg.equals("?")) { + for (String line : HELP_MSG.split("\n")) { + logDirect(line); + } + return false; + } if (msg.contains(" ")) { String[] data = msg.split(" "); if (data.length == 2) { @@ -151,21 +188,19 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("unable to parse integer " + ex); return true; } - pathingBehavior.setGoal(goal); + customGoalProcess.setGoal(goal); logDirect("Goal: " + goal); return true; } if (msg.equals("path")) { - if (!pathingBehavior.path()) { - if (pathingBehavior.getGoal() == null) { - logDirect("No goal."); - } else { - if (pathingBehavior.getGoal().isInGoal(playerFeet())) { - logDirect("Already in goal"); - } else { - logDirect("Currently executing a path. Please cancel it first."); - } - } + if (pathingBehavior.getGoal() == null) { + logDirect("No goal."); + } else if (pathingBehavior.getGoal().isInGoal(playerFeet())) { + logDirect("Already in goal"); + } else if (pathingBehavior.isPathing()) { + logDirect("Currently executing a path. Please cancel it first."); + } else { + customGoalProcess.setGoalAndPath(pathingBehavior.getGoal()); } return true; } @@ -179,7 +214,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { Chunk chunk = cli.getLoadedChunk(x, z); if (chunk != null) { count++; - WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().queueForPacking(chunk); + baritone.getWorldProvider().getCurrentWorld().getCachedWorld().queueForPacking(chunk); } } } @@ -187,21 +222,16 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return true; } if (msg.equals("axis")) { - pathingBehavior.setGoal(new GoalAxis()); - pathingBehavior.path(); + customGoalProcess.setGoalAndPath(new GoalAxis()); return true; } if (msg.equals("cancel") || msg.equals("stop")) { - baritone.getMineBehavior().cancel(); - baritone.getFollowBehavior().cancel(); - pathingBehavior.cancel(); + pathingBehavior.cancelEverything(); logDirect("ok canceled"); return true; } if (msg.equals("forcecancel")) { - baritone.getMineBehavior().cancel(); - baritone.getFollowBehavior().cancel(); - pathingBehavior.cancel(); + pathingBehavior.cancelEverything(); AbstractNodeCostSearch.forceCancel(); pathingBehavior.forceCancel(); logDirect("ok force canceled"); @@ -224,15 +254,17 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Inverting goal of player feet"); runAwayFrom = playerFeet(); } - pathingBehavior.setGoal(new GoalRunAway(1, runAwayFrom) { + customGoalProcess.setGoalAndPath(new GoalRunAway(1, runAwayFrom) { @Override - public boolean isInGoal(BlockPos pos) { + public boolean isInGoal(int x, int y, int z) { return false; } }); - if (!pathingBehavior.path()) { - logDirect("Currently executing a path. Please cancel it first."); - } + return true; + } + if (msg.startsWith("followplayers")) { + baritone.getFollowProcess().follow(EntityPlayer.class::isInstance); // O P P A + logDirect("Following any players"); return true; } if (msg.startsWith("follow")) { @@ -252,23 +284,24 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Not found"); return true; } - baritone.getFollowBehavior().follow(toFollow.get()); + Entity effectivelyFinal = toFollow.get(); + baritone.getFollowProcess().follow(x -> effectivelyFinal.equals(x)); logDirect("Following " + toFollow.get()); return true; } if (msg.equals("reloadall")) { - WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().reloadAllFromDisk(); + baritone.getWorldProvider().getCurrentWorld().getCachedWorld().reloadAllFromDisk(); logDirect("ok"); return true; } if (msg.equals("saveall")) { - WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().save(); + baritone.getWorldProvider().getCurrentWorld().getCachedWorld().save(); logDirect("ok"); return true; } if (msg.startsWith("find")) { String blockType = msg.substring(4).trim(); - LinkedList locs = WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, 4); + LinkedList locs = baritone.getWorldProvider().getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, 4); logDirect("Have " + locs.size() + " locations"); for (BlockPos pos : locs) { Block actually = BlockStateInterface.get(pos).getBlock(); @@ -284,7 +317,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { int quantity = Integer.parseInt(blockTypes[1]); Block block = ChunkPacker.stringToBlock(blockTypes[0]); Objects.requireNonNull(block); - baritone.getMineBehavior().mine(quantity, block); + baritone.getMineProcess().mine(quantity, block); logDirect("Will mine " + quantity + " " + blockTypes[0]); return true; } catch (NumberFormatException | ArrayIndexOutOfBoundsException | NullPointerException ex) {} @@ -295,14 +328,14 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } } - baritone.getMineBehavior().mine(0, blockTypes); + baritone.getMineProcess().mineByName(0, blockTypes); logDirect("Started mining blocks of type " + Arrays.toString(blockTypes)); return true; } if (msg.startsWith("thisway")) { try { Goal goal = GoalXZ.fromDirection(playerFeetAsVec(), player().rotationYaw, Double.parseDouble(msg.substring(7).trim())); - pathingBehavior.setGoal(goal); + customGoalProcess.setGoal(goal); logDirect("Goal: " + goal); } catch (NumberFormatException ex) { logDirect("Error unable to parse '" + msg.substring(7).trim() + "' to a double."); @@ -320,7 +353,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); return true; } - Set waypoints = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getByTag(tag); + Set waypoints = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getByTag(tag); // might as well show them from oldest to newest List sorted = new ArrayList<>(waypoints); sorted.sort(Comparator.comparingLong(IWaypoint::getCreationTimestamp)); @@ -348,7 +381,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } name = parts[0]; } - WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, Waypoint.Tag.USER, pos)); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, Waypoint.Tag.USER, pos)); logDirect("Saved user defined position " + pos + " under name '" + name + "'. Say 'goto " + name + "' to set goal, say 'list user' to list custom waypoints."); return true; } @@ -365,69 +398,59 @@ public class ExampleBaritoneControl extends Behavior implements Helper { Block block = ChunkPacker.stringToBlock(mining); //logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); if (block == null) { - waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getAllWaypoints().stream().filter(w -> w.getName().equalsIgnoreCase(mining)).max(Comparator.comparingLong(IWaypoint::getCreationTimestamp)).orElse(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"); return true; } } else { - List locs = baritone.getMineBehavior().searchWorld(Collections.singletonList(block), 64); - if (locs.isEmpty()) { - logDirect("No locations for " + mining + " known, cancelling"); - return true; - } - pathingBehavior.setGoal(new GoalComposite(locs.stream().map(GoalGetToBlock::new).toArray(Goal[]::new))); - pathingBehavior.path(); + baritone.getGetToBlockProcess().getToBlock(block); return true; } } else { - waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(tag); + waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(tag); if (waypoint == null) { logDirect("None saved for tag " + tag); return true; } } Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); - if (!pathingBehavior.path() && !goal.isInGoal(playerFeet())) { - logDirect("Currently executing a path. Please cancel it first."); - } + customGoalProcess.setGoalAndPath(goal); return true; } if (msg.equals("spawn") || msg.equals("bed")) { - IWaypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.BED); + IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.BED); if (waypoint == null) { BlockPos spawnPoint = player().getBedLocation(); // for some reason the default spawnpoint is underground sometimes Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getZ()); logDirect("spawn not saved, defaulting to world spawn. set goal to " + goal); - pathingBehavior.setGoal(goal); + customGoalProcess.setGoalAndPath(goal); } else { - Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); + Goal goal = new GoalGetToBlock(waypoint.getLocation()); + customGoalProcess.setGoalAndPath(goal); logDirect("Set goal to most recent bed " + goal); } return true; } if (msg.equals("sethome")) { - WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", Waypoint.Tag.HOME, playerFeet())); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", Waypoint.Tag.HOME, playerFeet())); logDirect("Saved. Say home to set goal."); return true; } if (msg.equals("home")) { - IWaypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.HOME); + IWaypoint waypoint = baritone.getWorldProvider().getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.HOME); if (waypoint == null) { logDirect("home not saved"); } else { Goal goal = new GoalBlock(waypoint.getLocation()); - pathingBehavior.setGoal(goal); - pathingBehavior.path(); + customGoalProcess.setGoalAndPath(goal); logDirect("Going to saved home " + goal); } return true; } if (msg.equals("costs")) { - List moves = Stream.of(Moves.values()).map(x -> x.apply0(playerFeet())).collect(Collectors.toCollection(ArrayList::new)); + List moves = Stream.of(Moves.values()).map(x -> x.apply0(new CalculationContext(), playerFeet())).collect(Collectors.toCollection(ArrayList::new)); while (moves.contains(null)) { moves.remove(null); } @@ -443,11 +466,6 @@ public class ExampleBaritoneControl extends Behavior implements Helper { } return true; } - if (msg.equals("pause")) { - boolean enabled = pathingBehavior.toggle(); - logDirect("Pathing Behavior has " + (enabled ? "resumed" : "paused") + "."); - return true; - } if (msg.equals("damn")) { logDirect("daniel"); } diff --git a/src/main/java/baritone/utils/Helper.java b/src/main/java/baritone/utils/Helper.java index 2a34ecc0..31b3fc10 100755 --- a/src/main/java/baritone/utils/Helper.java +++ b/src/main/java/baritone/utils/Helper.java @@ -23,6 +23,7 @@ import baritone.api.utils.Rotation; import net.minecraft.block.BlockSlab; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; @@ -51,10 +52,23 @@ public interface Helper { Minecraft mc = Minecraft.getMinecraft(); default EntityPlayerSP player() { + if (!mc.isCallingFromMinecraftThread()) { + throw new IllegalStateException("h00000000"); + } return mc.player; } + default PlayerControllerMP playerController() { // idk + if (!mc.isCallingFromMinecraftThread()) { + throw new IllegalStateException("h00000000"); + } + return mc.playerController; + } + default WorldClient world() { + if (!mc.isCallingFromMinecraftThread()) { + throw new IllegalStateException("h00000000"); + } return mc.world; } diff --git a/src/main/java/baritone/utils/InputOverrideHandler.java b/src/main/java/baritone/utils/InputOverrideHandler.java index 9cf7d1da..9c3eed7f 100755 --- a/src/main/java/baritone/utils/InputOverrideHandler.java +++ b/src/main/java/baritone/utils/InputOverrideHandler.java @@ -17,8 +17,13 @@ package baritone.utils; +import baritone.Baritone; +import baritone.api.event.events.TickEvent; +import baritone.behavior.Behavior; import net.minecraft.client.settings.KeyBinding; +import org.lwjgl.input.Keyboard; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -30,16 +35,16 @@ import java.util.Map; * @author Brady * @since 7/31/2018 11:20 PM */ -public final class InputOverrideHandler implements Helper { +public final class InputOverrideHandler extends Behavior implements Helper { + + public InputOverrideHandler(Baritone baritone) { + super(baritone); + } /** - * Maps keybinds to whether or not we are forcing their state down. + * Maps inputs to whether or not we are forcing their state down. */ - private final Map inputForceStateMap = new HashMap<>(); - - public final void clearAllKeys() { - inputForceStateMap.clear(); - } + private final Map inputForceStateMap = new HashMap<>(); /** * Returns whether or not we are forcing down the specified {@link KeyBinding}. @@ -48,7 +53,17 @@ public final class InputOverrideHandler implements Helper { * @return Whether or not it is being forced down */ public final boolean isInputForcedDown(KeyBinding key) { - return inputForceStateMap.getOrDefault(key, false); + return isInputForcedDown(Input.getInputForBind(key)); + } + + /** + * Returns whether or not we are forcing down the specified {@link Input}. + * + * @param input The input + * @return Whether or not it is being forced down + */ + public final boolean isInputForcedDown(Input input) { + return input == null ? false : this.inputForceStateMap.getOrDefault(input, false); } /** @@ -58,11 +73,47 @@ public final class InputOverrideHandler implements Helper { * @param forced Whether or not the state is being forced */ public final void setInputForceState(Input input, boolean forced) { - inputForceStateMap.put(input.getKeyBinding(), forced); + this.inputForceStateMap.put(input, forced); } /** - * An {@link Enum} representing the possible inputs that we may want to force. + * Clears the override state for all keys + */ + public final void clearAllKeys() { + this.inputForceStateMap.clear(); + } + + @Override + public final void onProcessKeyBinds() { + // Simulate the key being held down this tick + for (InputOverrideHandler.Input input : Input.values()) { + KeyBinding keyBinding = input.getKeyBinding(); + + if (isInputForcedDown(keyBinding) && !keyBinding.isKeyDown()) { + int keyCode = keyBinding.getKeyCode(); + + if (keyCode < Keyboard.KEYBOARD_SIZE) { + KeyBinding.onTick(keyCode < 0 ? keyCode + 100 : keyCode); + } + } + } + } + + @Override + public final void onTick(TickEvent event) { + if (event.getType() == TickEvent.Type.OUT) { + return; + } + if (Baritone.settings().leftClickWorkaround.get()) { + boolean stillClick = BlockBreakHelper.tick(isInputForcedDown(Input.CLICK_LEFT.keyBinding)); + setInputForceState(Input.CLICK_LEFT, stillClick); + } + } + + /** + * An {@link Enum} representing the inputs that control the player's + * behavior. This includes moving, interacting with blocks, jumping, + * sneaking, and sprinting. */ public enum Input { @@ -111,6 +162,11 @@ public final class InputOverrideHandler implements Helper { */ SPRINT(mc.gameSettings.keyBindSprint); + /** + * Map of {@link KeyBinding} to {@link Input}. Values should be queried through {@link #getInputForBind(KeyBinding)} + */ + private static final Map bindToInputMap = new HashMap<>(); + /** * The actual game {@link KeyBinding} being forced. */ @@ -126,5 +182,15 @@ public final class InputOverrideHandler implements Helper { public final KeyBinding getKeyBinding() { return this.keyBinding; } + + /** + * Finds the {@link Input} constant that is associated with the specified {@link KeyBinding}. + * + * @param binding The {@link KeyBinding} to find the associated {@link Input} for + * @return The {@link Input} associated with the specified {@link KeyBinding} + */ + public static Input getInputForBind(KeyBinding binding) { + return bindToInputMap.computeIfAbsent(binding, b -> Arrays.stream(values()).filter(input -> input.keyBinding == b).findFirst().orElse(null)); + } } } diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java new file mode 100644 index 00000000..9ea193a1 --- /dev/null +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -0,0 +1,194 @@ +/* + * 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 . + */ + +package baritone.utils; + +import baritone.Baritone; +import baritone.api.event.events.TickEvent; +import baritone.api.event.listener.AbstractGameEventListener; +import baritone.api.pathing.goals.Goal; +import baritone.api.process.IBaritoneProcess; +import baritone.api.process.PathingCommand; +import baritone.behavior.PathingBehavior; +import baritone.pathing.calc.AbstractNodeCostSearch; +import baritone.pathing.path.PathExecutor; +import net.minecraft.util.math.BlockPos; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class PathingControlManager { + private final Baritone baritone; + private final HashSet processes; // unGh + private IBaritoneProcess inControlLastTick; + private IBaritoneProcess inControlThisTick; + private PathingCommand command; + + public PathingControlManager(Baritone baritone) { + this.baritone = baritone; + this.processes = new HashSet<>(); + baritone.registerEventListener(new AbstractGameEventListener() { // needs to be after all behavior ticks + @Override + public void onTick(TickEvent event) { + if (event.getType() == TickEvent.Type.OUT) { + return; + } + postTick(); + } + }); + } + + public void registerProcess(IBaritoneProcess process) { + process.onLostControl(); // make sure it's reset + processes.add(process); + } + + public void cancelEverything() { + for (IBaritoneProcess proc : processes) { + proc.onLostControl(); + if (proc.isActive() && !proc.isTemporary()) { // it's okay for a temporary thing (like combat pause) to maintain control even if you say to cancel + // but not for a non temporary thing + throw new IllegalStateException(proc.displayName()); + } + } + } + + public IBaritoneProcess inControlThisTick() { + return inControlThisTick; + } + + public void preTick() { + inControlLastTick = inControlThisTick; + command = doTheStuff(); + if (command == null) { + return; + } + PathingBehavior p = baritone.getPathingBehavior(); + switch (command.commandType) { + case REQUEST_PAUSE: + p.requestPause(); + break; + case CANCEL_AND_SET_GOAL: + p.secretInternalSetGoal(command.goal); + p.cancelSegmentIfSafe(); + break; + case FORCE_REVALIDATE_GOAL_AND_PATH: + if (!p.isPathing() && !AbstractNodeCostSearch.getCurrentlyRunning().isPresent()) { + p.secretInternalSetGoalAndPath(command.goal); + } + break; + case REVALIDATE_GOAL_AND_PATH: + if (!p.isPathing() && !AbstractNodeCostSearch.getCurrentlyRunning().isPresent()) { + p.secretInternalSetGoalAndPath(command.goal); + } + break; + case SET_GOAL_AND_PATH: + // now this i can do + if (command.goal != null) { + baritone.getPathingBehavior().secretInternalSetGoalAndPath(command.goal); + } + break; + default: + throw new IllegalStateException(); + } + } + + public void postTick() { + // if we did this in pretick, it would suck + // we use the time between ticks as calculation time + // therefore, we only cancel and recalculate after the tick for the current path has executed + // "it would suck" means it would actually execute a path every other tick + if (command == null) { + return; + } + PathingBehavior p = baritone.getPathingBehavior(); + switch (command.commandType) { + case FORCE_REVALIDATE_GOAL_AND_PATH: + if (command.goal == null || forceRevalidate(command.goal) || revalidateGoal(command.goal)) { + // pwnage + p.softCancelIfSafe(); + } + p.secretInternalSetGoalAndPath(command.goal); + break; + case REVALIDATE_GOAL_AND_PATH: + if (Baritone.settings().cancelOnGoalInvalidation.get() && (command.goal == null || revalidateGoal(command.goal))) { + p.softCancelIfSafe(); + } + p.secretInternalSetGoalAndPath(command.goal); + break; + default: + } + } + + public boolean forceRevalidate(Goal newGoal) { + PathExecutor current = baritone.getPathingBehavior().getCurrent(); + if (current != null) { + if (newGoal.isInGoal(current.getPath().getDest())) { + return false; + } + return !newGoal.toString().equals(current.getPath().getGoal().toString()); + } + return false; + } + + public boolean revalidateGoal(Goal newGoal) { + PathExecutor current = baritone.getPathingBehavior().getCurrent(); + if (current != null) { + Goal intended = current.getPath().getGoal(); + BlockPos end = current.getPath().getDest(); + if (intended.isInGoal(end) && !newGoal.isInGoal(end)) { + // this path used to end in the goal + // but the goal has changed, so there's no reason to continue... + return true; + } + } + return false; + } + + + public PathingCommand doTheStuff() { + List inContention = processes.stream().filter(IBaritoneProcess::isActive).sorted(Comparator.comparingDouble(IBaritoneProcess::priority)).collect(Collectors.toList()); + boolean found = false; + boolean cancelOthers = false; + PathingCommand exec = null; + for (int i = inContention.size() - 1; i >= 0; i--) { // truly a gamer moment + IBaritoneProcess proc = inContention.get(i); + if (found) { + if (cancelOthers) { + proc.onLostControl(); + } + } else { + exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel()); + if (exec == null) { + if (proc.isActive()) { + throw new IllegalStateException(proc.displayName()); + } + proc.onLostControl(); + continue; + } + //System.out.println("Executing command " + exec.commandType + " " + exec.goal + " from " + proc.displayName()); + inControlThisTick = proc; + found = true; + cancelOthers = !proc.isTemporary(); + } + } + return exec; + } +} diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index 0c618294..026ec199 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -20,6 +20,7 @@ package baritone.utils; import baritone.Baritone; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.init.Enchantments; import net.minecraft.init.MobEffects; @@ -36,7 +37,7 @@ import java.util.function.Function; * * @author Avery, Brady, leijurv */ -public class ToolSet implements Helper { +public class ToolSet { /** * A cache mapping a {@link Block} to how long it will take to break * with this toolset, given the optimum tool is used. @@ -48,8 +49,11 @@ public class ToolSet implements Helper { */ private final Function backendCalculation; - public ToolSet() { + private final EntityPlayerSP player; + + public ToolSet(EntityPlayerSP player) { breakStrengthCache = new HashMap<>(); + this.player = player; if (Baritone.settings().considerPotionEffects.get()) { double amplifier = potionAmplifier(); @@ -98,7 +102,7 @@ public class ToolSet implements Helper { int materialCost = Integer.MIN_VALUE; IBlockState blockState = b.getDefaultState(); for (byte i = 0; i < 9; i++) { - ItemStack itemStack = player().inventory.getStackInSlot(i); + ItemStack itemStack = player.inventory.getStackInSlot(i); double v = calculateStrVsBlock(itemStack, blockState); if (v > value) { value = v; @@ -123,7 +127,7 @@ public class ToolSet implements Helper { * @return A double containing the destruction ticks with the best tool */ private double getBestDestructionTime(Block b) { - ItemStack stack = player().inventory.getStackInSlot(getBestSlot(b)); + ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b)); return calculateStrVsBlock(stack, b.getDefaultState()); } @@ -164,11 +168,11 @@ public class ToolSet implements Helper { */ private double potionAmplifier() { double speed = 1; - if (player().isPotionActive(MobEffects.HASTE)) { - speed *= 1 + (player().getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2; + if (player.isPotionActive(MobEffects.HASTE)) { + speed *= 1 + (player.getActivePotionEffect(MobEffects.HASTE).getAmplifier() + 1) * 0.2; } - if (player().isPotionActive(MobEffects.MINING_FATIGUE)) { - switch (player().getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) { + if (player.isPotionActive(MobEffects.MINING_FATIGUE)) { + switch (player.getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) { case 0: speed *= 0.3; break; diff --git a/src/main/java/baritone/utils/accessor/IAnvilChunkLoader.java b/src/main/java/baritone/utils/accessor/IAnvilChunkLoader.java index c243ae0e..8606bc3f 100644 --- a/src/main/java/baritone/utils/accessor/IAnvilChunkLoader.java +++ b/src/main/java/baritone/utils/accessor/IAnvilChunkLoader.java @@ -17,9 +17,13 @@ package baritone.utils.accessor; +import baritone.cache.WorldProvider; + import java.io.File; /** + * @see WorldProvider + * * @author Brady * @since 8/4/2018 11:36 AM */ diff --git a/src/main/java/baritone/utils/accessor/IChunkProviderServer.java b/src/main/java/baritone/utils/accessor/IChunkProviderServer.java index 78a471b2..176f05a3 100644 --- a/src/main/java/baritone/utils/accessor/IChunkProviderServer.java +++ b/src/main/java/baritone/utils/accessor/IChunkProviderServer.java @@ -17,9 +17,12 @@ package baritone.utils.accessor; +import net.minecraft.world.WorldProvider; import net.minecraft.world.chunk.storage.IChunkLoader; /** + * @see WorldProvider + * * @author Brady * @since 8/4/2018 11:33 AM */ diff --git a/src/main/java/baritone/utils/pathing/BetterWorldBorder.java b/src/main/java/baritone/utils/pathing/BetterWorldBorder.java index 8a5c79d5..9d8f3ef8 100644 --- a/src/main/java/baritone/utils/pathing/BetterWorldBorder.java +++ b/src/main/java/baritone/utils/pathing/BetterWorldBorder.java @@ -17,10 +17,14 @@ package baritone.utils.pathing; -import baritone.utils.Helper; import net.minecraft.world.border.WorldBorder; -public class BetterWorldBorder implements Helper { +/** + * Essentially, a "rule" for the path finder, prevents proposed movements from attempting to venture + * into the world border, and prevents actual movements from placing blocks in the world border. + */ +public class BetterWorldBorder { + private final double minX; private final double maxX; private final double minZ; diff --git a/src/main/java/baritone/utils/pathing/PathBase.java b/src/main/java/baritone/utils/pathing/PathBase.java new file mode 100644 index 00000000..aaf36895 --- /dev/null +++ b/src/main/java/baritone/utils/pathing/PathBase.java @@ -0,0 +1,52 @@ +/* + * 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 . + */ + +package baritone.utils.pathing; + +import baritone.api.BaritoneAPI; +import baritone.api.pathing.calc.IPath; +import baritone.api.pathing.goals.Goal; +import baritone.pathing.path.CutoffPath; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.EmptyChunk; + +public abstract class PathBase implements IPath { + @Override + public IPath cutoffAtLoadedChunks(World world) { + for (int i = 0; i < positions().size(); i++) { + BlockPos pos = positions().get(i); + if (world.getChunk(pos) instanceof EmptyChunk) { + return new CutoffPath(this, i); + } + } + return this; + } + + @Override + public IPath staticCutoff(Goal destination) { + if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) { + return this; + } + if (destination == null || destination.isInGoal(getDest())) { + return this; + } + double factor = BaritoneAPI.getSettings().pathCutoffFactor.get(); + int newLength = (int) ((length() - 1) * factor); + return new CutoffPath(this, newLength); + } +} diff --git a/src/main/java/baritone/utils/pathing/PathingBlockType.java b/src/main/java/baritone/utils/pathing/PathingBlockType.java index 80c92dcb..35e21fc3 100644 --- a/src/main/java/baritone/utils/pathing/PathingBlockType.java +++ b/src/main/java/baritone/utils/pathing/PathingBlockType.java @@ -42,18 +42,6 @@ public enum PathingBlockType { } public static PathingBlockType fromBits(boolean b1, boolean b2) { - if (b1) { - if (b2) { - return PathingBlockType.SOLID; - } else { - return PathingBlockType.AVOID; - } - } else { - if (b2) { - return PathingBlockType.WATER; - } else { - return PathingBlockType.AIR; - } - } + return b1 ? b2 ? SOLID : AVOID : b2 ? WATER : AIR; } }