diff --git a/.travis.yml b/.travis.yml index dff5f3a5..c54706cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1 +1,28 @@ language: java + +sudo: required + +services: +- docker + +install: +- travis_retry docker build -t cabaletta/baritone . + +script: +- docker run --name baritone cabaletta/baritone /bin/sh -c "set -e; /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 128x128x24 -ac +extension GLX +render; sh scripts/build.sh; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient" +- docker cp baritone:/code/dist dist +- ls dist +- cat dist/checksums.txt + +deploy: + provider: releases + api_key: + secure: YOuiXoJNpB4bW89TQoY2IGXg0tqOKls55YMXsSPU6Mx8WzRu8CjjO/A8KA9nGfNrKM+NucjiKr/h53O2Dp2uyy0i0SLvav/G0MaBMeB1NlPRwFopi6tVPNaoZsvr8NW4BIURhspckYLpOTYWnfmOkIv8q7AxrjUZWPKDlq0dte20UxEqUE6msHJ7U9XlKo/4fX40kvWMfwGI2hTyAtL0cRT1QPsd+uW3OQjAPcQj+jKaWld46V8pBK8g9Qde9mo8HC9NBv97zw1bBF1EFkynW569kElHvaS2Opl2QLGaf66guDbpnqDpGHMhQrDdxsZHJ4RksyITn+8A9UArmbkU35BxKqBeQqOWxod2+M0axdLh1pvX43Q1t9n7RiZBf7GvV8vkXL5Sjf8v6Y4LqkJGhvQkTUwpH+0knwrE761DMCtBC34AiWG70D4u7msmhurkflr9kmRHSj/3lyJ1Q2lkt8L+FOAlQBVs64vXTsfgc6Yge7N0O3UD5hCkrDNoz3BzhNBdCkbdxdKCGip71UZgUNkPy9o3ui8jATNj9ypx3+U8ovqP0XWlJqUZmyeXyNGW9NrLeCkRLTlLnZ/dv6OPONa1oAu4TwF1w5A+TGRFZcZjH/PnZKZDQ1OYQOR6drLKRYdr2unvuf5KUKUGqZ7aYtLGhP0rBvGWddRV7DSmX/s= + all_branches: true + file_glob: true + file: + - dist/* + skip_cleanup: true + on: + tags: true + repo: cabaletta/baritone diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..ac36eea5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +FROM debian:jessie + +RUN echo 'deb http://deb.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/jessie-backports.list + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt update -y + +RUN apt install --target-release jessie-backports \ + openjdk-8-jdk \ + ca-certificates-java \ + --assume-yes + +RUN apt install -qq --force-yes mesa-utils libgl1-mesa-glx libxcursor1 libxrandr2 libxxf86vm1 x11-xserver-utils xfonts-base xserver-common + +RUN apt install -qq --force-yes unzip wget + +ADD . /code + +RUN echo "\nrunClient {\nargs \"--width\",\"128\",\"--height\",\"128\"\n}" >> /code/build.gradle + +# this .deb is specially patched to support lwjgl +# source: https://github.com/tectonicus/tectonicus/issues/60#issuecomment-154239173 +RUN dpkg -i /code/scripts/xvfb_1.16.4-1_amd64.deb + +WORKDIR /code + +RUN ./gradlew build \ No newline at end of file diff --git a/IMPACT.md b/IMPACT.md index 357119a1..e8430ab5 100644 --- a/IMPACT.md +++ b/IMPACT.md @@ -11,9 +11,12 @@ There are some basic steps to getting Baritone setup with Impact. ## Acquiring a build of Baritone There are 3 methods of acquiring a build of Baritone (While it is still in development) -### Official Build (Not always up to date) -Download the "official" jar (as of commit 2e63ac4, -built on September 19) from here. +### Official Release (Not always up to date) +https://github.com/cabaletta/baritone/releases + +For Impact 4.3, there is no Baritone integration yet, so you will want `baritone-standalone-X.Y.Z.jar`. + +Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`. ### Building Baritone yourself There are a few steps to this @@ -23,7 +26,7 @@ There are a few steps to this command line - Windows: ``gradlew build`` - Mac/Linux: ``./gradlew build`` -- The build should be exported into ``/build/libs/baritone-1.0.0.jar`` +- The build should be exported into ``/build/libs/baritone-X.Y.Z.jar`` ### Cutting Edge Release If you want to trust @Plutie#9079, you can download an automatically generated build of the latest commit @@ -37,9 +40,9 @@ putting baritone. - Create 3 new subdirectories starting from ``libraries`` - ``cabaletta`` - ``baritone`` - - ``1.0.0`` - - Copy the build of Baritone that was acquired earlier, and place it into the ``1.0.0`` folder - - The full path should look like ``/libraries/cabaletta/baritone/1.0.0/baritone-1.0.0.jar`` + - ``X.Y.Z`` + - Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder + - The full path should look like ``/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar`` ## Modifying the Impact Profile JSON to run baritone The final step is "registering" the Baritone library with Impact, so that it loads on launch. @@ -72,7 +75,7 @@ The final step is "registering" the Baritone library with Impact, so that it loa - Create a new object in the array, between the ``Impact`` and ``ClientAPI`` dependencies preferably. ``` { - "name": "cabaletta:baritone:1.0.0" + "name": "cabaletta:baritone:X.Y.Z" }, ``` - Now find the ``"minecraftArguments": "..."`` text near the top. diff --git a/README.md b/README.md index c2c82200..ad6980f6 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,19 @@ [![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/7150d8ccf6094057b1782aa7a8f92d7d)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade) -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. - -Features - -Baritone + Impact - Unofficial Jenkins: [![Build Status](https://plutiejenkins.leijurv.com/job/baritone/badge/icon)](https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/) +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). + +Here are some links to help to get started: + +- [Features](FEATURES.md) + +- [Baritone + Impact](IMPACT.md) + +There's also some useful information down below + # Setup ## IntelliJ's Gradle UI @@ -38,18 +42,18 @@ $ gradlew genIntellijRuns ``` # Chat control -Defined here +[Defined Here](src/main/java/baritone/utils/ExampleBaritoneControl.java) Quick start example: `thisway 1000` or `goal 70` to set the goal, `path` to actually start pathing. Also try `mine diamond_ore`. `cancel` to cancel. # API example ``` -Baritone.settings().allowSprint.value = true; -Baritone.settings().pathTimeoutMS.value = 2000L; +BaritoneAPI.getSettings().allowSprint.value = true; +BaritoneAPI.getSettings().pathTimeoutMS.value = 2000L; -PathingBehavior.INSTANCE.setGoal(new GoalXZ(10000, 20000)); -PathingBehavior.INSTANCE.path(); +BaritoneAPI.getPathingBehavior().setGoal(new GoalXZ(10000, 20000)); +BaritoneAPI.getPathingBehavior().path(); ``` # FAQ @@ -60,8 +64,8 @@ Sure! (As long as usage is in compliance with the LGPL 3 License) ## How is it so fast? -Magic +Magic. (Hours of [Leijurv](https://github.com/leijurv) enduring excruciating pain) ## Why is it called Baritone? -It's named for FitMC's deep sultry voice. \ No newline at end of file +It's named for FitMC's deep sultry voice. diff --git a/build.gradle b/build.gradle index 1b31aae8..0a1bb804 100755 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ */ group 'baritone' -version '1.0.0' +version '0.0.3' buildscript { repositories { diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100644 index 00000000..a224a884 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,30 @@ +set -e # this makes the whole script fail immediately if any one of these commands fails +./gradlew build +export VERSION=$(cat build.gradle | grep "version '" | cut -d "'" -f 2-2) + +wget -nv https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip +unzip proguard6.0.3.zip 2>&1 > /dev/null +cd build/libs +echo "-injars 'baritone-$VERSION.jar'" >> api.pro # insert current version +cat ../../scripts/proguard.pro | grep -v "this is the rt jar" | grep -v "\-injars" >> api.pro # remove default rt jar and injar lines +echo "-libraryjars '$(java -verbose 2>/dev/null | sed -ne '1 s/\[Opened \(.*\)\]/\1/p')'" >> api.pro # insert correct rt.jar location +tail api.pro # debug, print out what the previous two commands generated +cat api.pro | grep -v "\-keep class baritone.api" > standalone.pro # standalone doesn't keep baritone api + +#wget -nv https://www.dropbox.com/s/zmc2l3jnwdvzvak/tempLibraries.zip?dl=1 # i'm sorry +#mv tempLibraries.zip?dl=1 tempLibraries.zip +#unzip tempLibraries.zip + +#instead of downloading these jars from my dropbox in a zip, just assume gradle's already got them for us +mkdir -p tempLibraries +cat ../../scripts/proguard.pro | grep tempLibraries | grep .jar | cut -d "/" -f 2- | cut -d "'" -f -1 | xargs -n1 -I{} bash -c "find ~/.gradle -name {}" | tee /dev/stderr | xargs -n1 -I{} cp {} tempLibraries + +mkdir ../../dist +java -jar ../../proguard6.0.3/lib/proguard.jar @api.pro +mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-api-$VERSION.jar +java -jar ../../proguard6.0.3/lib/proguard.jar @standalone.pro +mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-standalone-$VERSION.jar +mv baritone-$VERSION.jar ../../dist/baritone-unoptimized-$VERSION.jar +cd ../../dist +shasum * | tee checksums.txt +cd .. \ No newline at end of file diff --git a/proguard.pro b/scripts/proguard.pro similarity index 94% rename from proguard.pro rename to scripts/proguard.pro index 8880de6e..28120808 100644 --- a/proguard.pro +++ b/scripts/proguard.pro @@ -1,28 +1,28 @@ --injars baritone-1.0.0.jar +-injars baritone-0.0.3.jar -outjars Obfuscated -keepattributes Signature -keepattributes *Annotation* --optimizationpasses 20 +-optimizationpasses 5 -verbose -allowaccessmodification # anything not kept can be changed from public to private and inlined etc -overloadaggressively -dontusemixedcaseclassnames -# instead of obfing to a, b, c, obf to baritone.a, baritone.b, baritone.c so as to not conflict with minecraft's obfd classes +# instead of renaming to a, b, c, rename to baritone.a, baritone.b, baritone.c so as to not conflict with minecraft's obfd classes -flattenpackagehierarchy -repackageclasses 'baritone' #-keep class baritone.behavior.** { *; } -#-keep class baritone.api.** { *; } +-keep class baritone.api.** { *; } #-keep class baritone.* { *; } #-keep class baritone.pathing.goals.** { *; } # setting names are reflected from field names, so keep field names --keepclassmembers class baritone.Settings { +-keepclassmembers class baritone.api.Settings { public ; } @@ -30,9 +30,9 @@ -keep class baritone.launch.** { *; } # copy all necessary libraries into tempLibraries to build --libraryjars '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/rt.jar' +-libraryjars '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/rt.jar' # this is the rt jar --libraryjars 'tempLibraries/1.12.2.jar' +-libraryjars 'tempLibraries/minecraft-1.12.2.jar' -libraryjars 'tempLibraries/authlib-1.5.25.jar' -libraryjars 'tempLibraries/codecjorbis-20101023.jar' @@ -48,22 +48,18 @@ -libraryjars 'tempLibraries/httpclient-4.3.3.jar' -libraryjars 'tempLibraries/httpcore-4.3.2.jar' -libraryjars 'tempLibraries/icu4j-core-mojang-51.2.jar' --libraryjars 'tempLibraries/java-objc-bridge-1.0.0-natives-osx.jar' -libraryjars 'tempLibraries/java-objc-bridge-1.0.0.jar' -libraryjars 'tempLibraries/jinput-2.0.5.jar' --libraryjars 'tempLibraries/jinput-platform-2.0.5-natives-osx.jar' -libraryjars 'tempLibraries/jna-4.4.0.jar' -libraryjars 'tempLibraries/jopt-simple-5.0.3.jar' --libraryjars 'tempLibraries/jsr305-3.0.1-sources.jar' -libraryjars 'tempLibraries/jsr305-3.0.1.jar' -libraryjars 'tempLibraries/jutils-1.0.0.jar' -libraryjars 'tempLibraries/libraryjavasound-20101123.jar' -libraryjars 'tempLibraries/librarylwjglopenal-20100824.jar' -libraryjars 'tempLibraries/log4j-api-2.8.1.jar' -libraryjars 'tempLibraries/log4j-core-2.8.1.jar' --libraryjars 'tempLibraries/lwjgl-2.9.2-nightly-20140822.jar' --libraryjars 'tempLibraries/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar' --libraryjars 'tempLibraries/lwjgl_util-2.9.2-nightly-20140822.jar' +-libraryjars 'tempLibraries/lwjgl-2.9.4-nightly-20150209.jar' +-libraryjars 'tempLibraries/lwjgl_util-2.9.4-nightly-20150209.jar' -libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar' -libraryjars 'tempLibraries/oshi-core-1.1.jar' -libraryjars 'tempLibraries/patchy-1.1.jar' @@ -72,8 +68,8 @@ -libraryjars 'tempLibraries/soundsystem-20120107.jar' -libraryjars 'tempLibraries/text2speech-1.10.3.jar' --libraryjars 'tempLibraries/mixin-0.7.8-SNAPSHOT.jar' --libraryjars 'tempLibraries/launchwrapper-1.12.jar' +-libraryjars 'tempLibraries/mixin-0.7.11-SNAPSHOT.jar' +-libraryjars 'tempLibraries/launchwrapper-1.11.jar' # TODO why does only 1.11.jar exist? diff --git a/scripts/xvfb_1.16.4-1_amd64.deb b/scripts/xvfb_1.16.4-1_amd64.deb new file mode 100644 index 00000000..c3ef3de4 Binary files /dev/null and b/scripts/xvfb_1.16.4-1_amd64.deb differ diff --git a/src/api/java/baritone/api/BaritoneAPI.java b/src/api/java/baritone/api/BaritoneAPI.java new file mode 100644 index 00000000..aa9491db --- /dev/null +++ b/src/api/java/baritone/api/BaritoneAPI.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; + +import baritone.api.behavior.*; +import baritone.api.cache.IWorldProvider; + +/** + * API exposure for various things implemented in Baritone. + *

+ * W.I.P + * + * @author Brady + * @since 9/23/2018 + */ +public class BaritoneAPI { + + // General + private static final Settings settings = new Settings(); + private static IWorldProvider worldProvider; + + // Behaviors + private static IFollowBehavior followBehavior; + private static ILookBehavior lookBehavior; + private static IMemoryBehavior memoryBehavior; + private static IMineBehavior mineBehavior; + private static IPathingBehavior pathingBehavior; + + public static IFollowBehavior getFollowBehavior() { + return followBehavior; + } + + public static ILookBehavior getLookBehavior() { + return lookBehavior; + } + + public static IMemoryBehavior getMemoryBehavior() { + return memoryBehavior; + } + + public static IMineBehavior getMineBehavior() { + return mineBehavior; + } + + public static IPathingBehavior getPathingBehavior() { + return pathingBehavior; + } + + public static Settings getSettings() { + return settings; + } + + public static IWorldProvider getWorldProvider() { + return worldProvider; + } + + /** + * FOR INTERNAL USE ONLY + */ + public static void registerProviders( + IWorldProvider worldProvider + ) { + BaritoneAPI.worldProvider = worldProvider; + } + + /** + * FOR INTERNAL USE ONLY + */ + // @formatter:off + public static void registerDefaultBehaviors( + IFollowBehavior followBehavior, + ILookBehavior lookBehavior, + IMemoryBehavior memoryBehavior, + IMineBehavior mineBehavior, + IPathingBehavior pathingBehavior + ) { + BaritoneAPI.followBehavior = followBehavior; + BaritoneAPI.lookBehavior = lookBehavior; + BaritoneAPI.memoryBehavior = memoryBehavior; + BaritoneAPI.mineBehavior = mineBehavior; + BaritoneAPI.pathingBehavior = pathingBehavior; + } + // @formatter:on +} diff --git a/src/main/java/baritone/Settings.java b/src/api/java/baritone/api/Settings.java similarity index 91% rename from src/main/java/baritone/Settings.java rename to src/api/java/baritone/api/Settings.java index 87bd1812..ab758f40 100644 --- a/src/main/java/baritone/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -15,15 +15,17 @@ * along with Baritone. If not, see . */ -package baritone; +package baritone.api; -import baritone.utils.Helper; +import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.util.text.ITextComponent; +import java.awt.*; import java.lang.reflect.Field; import java.util.*; +import java.util.List; import java.util.function.Consumer; /** @@ -32,6 +34,7 @@ import java.util.function.Consumer; * @author leijurv */ public class Settings { + /** * Allow Baritone to break blocks */ @@ -320,8 +323,9 @@ public class Settings { public Setting prefix = new Setting<>(false); /** - * true: can mine blocks when in inventory, chat, or tabbed away in ESC menu - * false: works on cosmic prisons + * {@code true}: can mine blocks when in inventory, chat, or tabbed away in ESC menu + *

+ * {@code false}: works on cosmic prisons *

* LOL */ @@ -389,9 +393,51 @@ public class Settings { public Setting followRadius = new Setting<>(3); /** - * Instead of Baritone logging to chat, set a custom consumer. + * The function that is called when Baritone will log to chat. This function can be added to + * via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting + * {@link Setting#value}; */ - public Setting> logger = new Setting<>(new Helper() {}::addToChat); + public Setting> logger = new Setting<>(Minecraft.getMinecraft().ingameGUI.getChatGUI()::printChatMessage); + + /** + * The color of the current path + */ + public Setting colorCurrentPath = new Setting<>(Color.RED); + + /** + * The color of the next path + */ + public Setting colorNextPath = new Setting<>(Color.MAGENTA); + + /** + * The color of the blocks to break + */ + public Setting colorBlocksToBreak = new Setting<>(Color.RED); + + /** + * The color of the blocks to place + */ + public Setting colorBlocksToPlace = new Setting<>(Color.GREEN); + + /** + * The color of the blocks to walk into + */ + public Setting colorBlocksToWalkInto = new Setting<>(Color.MAGENTA); + + /** + * The color of the best path so far + */ + public Setting colorBestPathSoFar = new Setting<>(Color.BLUE); + + /** + * The color of the path to the most recent considered node + */ + public Setting colorMostRecentConsidered = new Setting<>(Color.CYAN); + + /** + * The color of the goal box + */ + public Setting colorGoalBox = new Setting<>(Color.GREEN); public final Map> byLowerName; public final List> allSettings; diff --git a/src/api/java/baritone/api/behavior/IBehavior.java b/src/api/java/baritone/api/behavior/IBehavior.java new file mode 100644 index 00000000..aee144e2 --- /dev/null +++ b/src/api/java/baritone/api/behavior/IBehavior.java @@ -0,0 +1,27 @@ +/* + * 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.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 {} diff --git a/src/api/java/baritone/api/behavior/IFollowBehavior.java b/src/api/java/baritone/api/behavior/IFollowBehavior.java new file mode 100644 index 00000000..c960fab3 --- /dev/null +++ b/src/api/java/baritone/api/behavior/IFollowBehavior.java @@ -0,0 +1,44 @@ +/* + * 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.behavior; + +import net.minecraft.entity.Entity; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface IFollowBehavior extends IBehavior { + + /** + * Set the follow target to the specified entity; + * + * @param entity The entity to follow + */ + void follow(Entity entity); + + /** + * @return The entity that is currently being followed + */ + Entity following(); + + /** + * Cancels the follow behavior, this will clear the current follow target. + */ + void cancel(); +} diff --git a/src/api/java/baritone/api/behavior/ILookBehavior.java b/src/api/java/baritone/api/behavior/ILookBehavior.java new file mode 100644 index 00000000..b5b5d63b --- /dev/null +++ b/src/api/java/baritone/api/behavior/ILookBehavior.java @@ -0,0 +1,39 @@ +/* + * 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.behavior; + +import baritone.api.utils.Rotation; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface ILookBehavior extends IBehavior { + + /** + * Updates the current {@link ILookBehavior} target to target + * the specified rotations on the next tick. If force is {@code true}, + * then freeLook will be overriden and angles will be set regardless. + * If any sort of block interaction is required, force should be {@code true}, + * otherwise, it should be {@code false}; + * + * @param rotation The target 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/IMemoryBehavior.java b/src/api/java/baritone/api/behavior/IMemoryBehavior.java new file mode 100644 index 00000000..ea5e9007 --- /dev/null +++ b/src/api/java/baritone/api/behavior/IMemoryBehavior.java @@ -0,0 +1,36 @@ +/* + * 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.behavior; + +import baritone.api.behavior.memory.IRememberedInventory; +import net.minecraft.util.math.BlockPos; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface IMemoryBehavior extends IBehavior { + + /** + * Gets a remembered inventory by its block position. + * + * @param pos The position of the container block + * @return The remembered inventory + */ + IRememberedInventory getInventoryByPos(BlockPos pos); +} diff --git a/src/api/java/baritone/api/behavior/IMineBehavior.java b/src/api/java/baritone/api/behavior/IMineBehavior.java new file mode 100644 index 00000000..78ab6d6a --- /dev/null +++ b/src/api/java/baritone/api/behavior/IMineBehavior.java @@ -0,0 +1,70 @@ +/* + * 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.behavior; + +import net.minecraft.block.Block; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface IMineBehavior extends IBehavior { + + /** + * Begin to search for and mine the specified blocks until + * the number of specified items to get from the blocks that + * 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 + */ + void mine(int quantity, String... blocks); + + /** + * Begin to search for and mine the specified blocks until + * the number of specified items to get from the blocks that + * 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 + */ + void mine(int quantity, Block... blocks); + + /** + * Begin to search for and mine the specified blocks. + * + * @param blocks The blocks to mine + */ + default void mine(String... blocks) { + this.mine(0, blocks); + } + + /** + * Begin to search for and mine the specified blocks. + * + * @param blocks The blocks to mine + */ + default void mine(Block... blocks) { + this.mine(0, blocks); + } + + /** + * Cancels the current mining task + */ + void cancel(); +} diff --git a/src/api/java/baritone/api/behavior/IPathingBehavior.java b/src/api/java/baritone/api/behavior/IPathingBehavior.java new file mode 100644 index 00000000..e21d999d --- /dev/null +++ b/src/api/java/baritone/api/behavior/IPathingBehavior.java @@ -0,0 +1,68 @@ +/* + * 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.behavior; + +import baritone.api.pathing.goals.Goal; + +import java.util.Optional; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface IPathingBehavior extends IBehavior { + + /** + * Returns the estimated remaining ticks in the current pathing + * segment. Given that the return type is an optional, {@link Optional#empty()} + * will be returned in the case that there is no current segment being pathed. + * + * @return The estimated remaining ticks in the current segment. + */ + 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. + */ + void cancel(); +} diff --git a/src/api/java/baritone/api/behavior/memory/IRememberedInventory.java b/src/api/java/baritone/api/behavior/memory/IRememberedInventory.java new file mode 100644 index 00000000..c57ded91 --- /dev/null +++ b/src/api/java/baritone/api/behavior/memory/IRememberedInventory.java @@ -0,0 +1,39 @@ +/* + * 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.behavior.memory; + +import net.minecraft.item.ItemStack; + +import java.util.List; + +/** + * @author Brady + * @since 9/23/2018 + */ +public interface IRememberedInventory { + + /** + * @return The contents of this inventory + */ + List getContents(); + + /** + * @return The number of slots in this inventory + */ + int getSize(); +} diff --git a/src/main/java/baritone/utils/pathing/IBlockTypeAccess.java b/src/api/java/baritone/api/cache/IBlockTypeAccess.java similarity index 89% rename from src/main/java/baritone/utils/pathing/IBlockTypeAccess.java rename to src/api/java/baritone/api/cache/IBlockTypeAccess.java index 4e34596a..242ff154 100644 --- a/src/main/java/baritone/utils/pathing/IBlockTypeAccess.java +++ b/src/api/java/baritone/api/cache/IBlockTypeAccess.java @@ -15,9 +15,8 @@ * along with Baritone. If not, see . */ -package baritone.utils.pathing; +package baritone.api.cache; -import baritone.utils.Helper; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.BlockPos; @@ -25,7 +24,7 @@ import net.minecraft.util.math.BlockPos; * @author Brady * @since 8/4/2018 2:01 AM */ -public interface IBlockTypeAccess extends Helper { +public interface IBlockTypeAccess { IBlockState getBlock(int x, int y, int z); diff --git a/src/api/java/baritone/api/cache/ICachedRegion.java b/src/api/java/baritone/api/cache/ICachedRegion.java new file mode 100644 index 00000000..5f9199fa --- /dev/null +++ b/src/api/java/baritone/api/cache/ICachedRegion.java @@ -0,0 +1,49 @@ +/* + * 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.cache; + +/** + * @author Brady + * @since 9/24/2018 + */ +public interface ICachedRegion extends IBlockTypeAccess { + + /** + * Returns whether or not the block at the specified X and Z coordinates + * is cached in this world. Similar to {@link ICachedWorld#isCached(int, int)}, + * 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 + */ + boolean isCached(int blockX, int blockZ); + + /** + * The X coordinate of this region + */ + int getX(); + + /** + * The Z coordinate of this region + */ + int getZ(); +} diff --git a/src/api/java/baritone/api/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java new file mode 100644 index 00000000..f8196ebb --- /dev/null +++ b/src/api/java/baritone/api/cache/ICachedWorld.java @@ -0,0 +1,82 @@ +/* + * 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.cache; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.Chunk; + +import java.util.LinkedList; + +/** + * @author Brady + * @since 9/24/2018 + */ +public interface ICachedWorld { + + /** + * Returns the region at the specified region coordinates + * + * @param regionX The region X coordinate + * @param regionZ The region Z coordinate + * @return The region located at the specified coordinates + */ + ICachedRegion getRegion(int regionX, int regionZ); + + /** + * Queues the specified chunk for packing. This entails reading the contents + * of the chunk, then packing the data into the 2-bit format, and storing that + * in this cached world. + * + * @param chunk The chunk to pack and store + */ + void queueForPacking(Chunk chunk); + + /** + * Returns whether or not the block at the specified X and Z coordinates + * is cached in this world. + * + * @param blockX The block X coordinate + * @param blockZ The block Z coordinate + * @return Whether or not the specified XZ location is cached + */ + boolean isCached(int blockX, int blockZ); + + /** + * Scans the cached chunks for location of the specified special block. The + * 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 maxRegionDistanceSq The maximum region distance, squared + * @return The locations found that match the special block + */ + LinkedList getLocationsOf(String block, int maximum, int maxRegionDistanceSq); + + /** + * Reloads all of the cached regions in this world from disk. Anything that is not saved + * will be lost. This operation does not execute in a new thread by default. + */ + void reloadAllFromDisk(); + + /** + * Saves all of the cached regions in this world to disk. This operation does not execute + * in a new thread by default. + */ + void save(); +} diff --git a/src/api/java/baritone/api/cache/IWaypoint.java b/src/api/java/baritone/api/cache/IWaypoint.java new file mode 100644 index 00000000..01df2a48 --- /dev/null +++ b/src/api/java/baritone/api/cache/IWaypoint.java @@ -0,0 +1,111 @@ +/* + * 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.cache; + +import net.minecraft.util.math.BlockPos; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * A marker for a position in the world. + * + * @author Brady + * @since 9/24/2018 + */ +public interface IWaypoint { + + /** + * @return The label for this waypoint + */ + String getName(); + + /** + * Returns the tag for this waypoint. The tag is a category + * for the waypoint in a sense, it describes the source of + * the waypoint. + * + * @return The waypoint tag + */ + Tag getTag(); + + /** + * Returns the unix epoch time in milliseconds that this waypoint + * was created. This value should only be set once, when the waypoint + * is initially created, and not when it is being loaded from file. + * + * @return The unix epoch milliseconds that this waypoint was created + */ + long getCreationTimestamp(); + + /** + * Returns the actual block position of this waypoint. + * + * @return The block position of this waypoint + */ + BlockPos getLocation(); + + enum Tag { + + /** + * Tag indicating a position explictly marked as a home base + */ + HOME("home", "base"), + + /** + * Tag indicating a position that the local player has died at + */ + DEATH("death"), + + /** + * Tag indicating a bed position + */ + BED("bed", "spawn"), + + /** + * Tag indicating that the waypoint was user-created + */ + USER("user"); + + /** + * A list of all of the + */ + private static final List TAG_LIST = Collections.unmodifiableList(Arrays.asList(Tag.values())); + + /** + * The names for the tag, anything that the tag can be referred to as. + */ + private final String[] names; + + Tag(String... names) { + this.names = names; + } + + /** + * Finds a tag from one of the names that could be used to identify said tag. + * + * @param name The name of the tag + * @return The tag, if one is found, otherwise, {@code null} + */ + public static Tag fromString(String name) { + return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null); + } + } +} diff --git a/src/api/java/baritone/api/cache/IWaypointCollection.java b/src/api/java/baritone/api/cache/IWaypointCollection.java new file mode 100644 index 00000000..051b199e --- /dev/null +++ b/src/api/java/baritone/api/cache/IWaypointCollection.java @@ -0,0 +1,68 @@ +/* + * 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.cache; + +import java.util.Set; + +/** + * @author Brady + * @since 9/24/2018 + */ +public interface IWaypointCollection { + + /** + * Adds a waypoint to this collection + * + * @param waypoint The waypoint + */ + void addWaypoint(IWaypoint waypoint); + + /** + * Removes a waypoint from this collection + * + * @param waypoint The waypoint + */ + void removeWaypoint(IWaypoint waypoint); + + /** + * Gets the most recently created waypoint by the specified {@link IWaypoint.Tag} + * + * @param tag The tag + * @return The most recently created waypoint with the specified tag + */ + IWaypoint getMostRecentByTag(IWaypoint.Tag tag); + + /** + * 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 + */ + 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 + */ + Set getAllWaypoints(); +} diff --git a/src/api/java/baritone/api/cache/IWorldData.java b/src/api/java/baritone/api/cache/IWorldData.java new file mode 100644 index 00000000..1031ba92 --- /dev/null +++ b/src/api/java/baritone/api/cache/IWorldData.java @@ -0,0 +1,39 @@ +/* + * 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.cache; + +/** + * @author Brady + * @since 9/24/2018 + */ +public interface IWorldData { + + /** + * Returns the cached world for this world. A cached world is a simplified format + * of a regular world, intended for use on multiplayer servers where chunks are not + * traditionally stored to disk, allowing for long distance pathing with minimal disk usage. + */ + ICachedWorld getCachedWorld(); + + /** + * Returns the waypoint collection for this world. + * + * @return The waypoint collection for this world + */ + IWaypointCollection getWaypoints(); +} diff --git a/src/api/java/baritone/api/cache/IWorldProvider.java b/src/api/java/baritone/api/cache/IWorldProvider.java new file mode 100644 index 00000000..0e54ef46 --- /dev/null +++ b/src/api/java/baritone/api/cache/IWorldProvider.java @@ -0,0 +1,32 @@ +/* + * 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.cache; + +/** + * @author Brady + * @since 9/24/2018 + */ +public interface IWorldProvider { + + /** + * Returns the data of the currently loaded world + * + * @return The current world data + */ + IWorldData getCurrentWorld(); +} diff --git a/src/main/java/baritone/pathing/goals/Goal.java b/src/api/java/baritone/api/pathing/goals/Goal.java similarity index 76% rename from src/main/java/baritone/pathing/goals/Goal.java rename to src/api/java/baritone/api/pathing/goals/Goal.java index 7f44d3d5..38cfb9d7 100644 --- a/src/main/java/baritone/pathing/goals/Goal.java +++ b/src/api/java/baritone/api/pathing/goals/Goal.java @@ -15,9 +15,8 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.pathing.movement.ActionCosts; import net.minecraft.util.math.BlockPos; /** @@ -25,22 +24,28 @@ import net.minecraft.util.math.BlockPos; * * @author leijurv */ -public interface Goal extends ActionCosts { +public interface Goal { /** * Returns whether or not the specified position * meets the requirement for this goal based. * - * @param pos The position * @return Whether or not it satisfies this goal */ - boolean isInGoal(BlockPos pos); + boolean isInGoal(int x, int y, int z); /** * Estimate the number of ticks it will take to get to the goal * - * @param pos The * @return The estimate number of ticks to satisfy the goal */ - double heuristic(BlockPos pos); + double heuristic(int x, int y, int z); + + default boolean isInGoal(BlockPos pos) { + return isInGoal(pos.getX(), pos.getY(), pos.getZ()); + } + + default double heuristic(BlockPos pos) { + return heuristic(pos.getX(), pos.getY(), pos.getZ()); + } } diff --git a/src/main/java/baritone/pathing/goals/GoalAxis.java b/src/api/java/baritone/api/pathing/goals/GoalAxis.java similarity index 64% rename from src/main/java/baritone/pathing/goals/GoalAxis.java rename to src/api/java/baritone/api/pathing/goals/GoalAxis.java index bd8f7c69..d8811cf9 100644 --- a/src/main/java/baritone/pathing/goals/GoalAxis.java +++ b/src/api/java/baritone/api/pathing/goals/GoalAxis.java @@ -15,28 +15,23 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.Baritone; -import net.minecraft.util.math.BlockPos; +import baritone.api.BaritoneAPI; public class GoalAxis implements Goal { private static final double SQRT_2_OVER_2 = Math.sqrt(2) / 2; @Override - public boolean isInGoal(BlockPos pos) { - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); - return y == Baritone.settings().axisHeight.get() && (x == 0 || z == 0 || Math.abs(x) == Math.abs(z)); + public boolean isInGoal(int x, int y, int z) { + return y == BaritoneAPI.getSettings().axisHeight.get() && (x == 0 || z == 0 || Math.abs(x) == Math.abs(z)); } @Override - public double heuristic(BlockPos pos) { - int x = Math.abs(pos.getX()); - int y = pos.getY(); - int z = Math.abs(pos.getZ()); + public double heuristic(int x0, int y, int z0) { + int x = Math.abs(x0); + int z = Math.abs(z0); int shrt = Math.min(x, z); int lng = Math.max(x, z); @@ -44,7 +39,7 @@ public class GoalAxis implements Goal { double flatAxisDistance = Math.min(x, Math.min(z, diff * SQRT_2_OVER_2)); - return flatAxisDistance * Baritone.settings().costHeuristic.get() + GoalYLevel.calculate(Baritone.settings().axisHeight.get(), y); + return flatAxisDistance * BaritoneAPI.getSettings().costHeuristic.get() + GoalYLevel.calculate(BaritoneAPI.getSettings().axisHeight.get(), y); } @Override diff --git a/src/main/java/baritone/pathing/goals/GoalBlock.java b/src/api/java/baritone/api/pathing/goals/GoalBlock.java similarity index 85% rename from src/main/java/baritone/pathing/goals/GoalBlock.java rename to src/api/java/baritone/api/pathing/goals/GoalBlock.java index 82515758..e0a60b59 100644 --- a/src/main/java/baritone/pathing/goals/GoalBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalBlock.java @@ -15,9 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.utils.interfaces.IGoalRenderPos; +import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; /** @@ -53,15 +53,15 @@ public class GoalBlock implements Goal, IGoalRenderPos { } @Override - public boolean isInGoal(BlockPos pos) { - return pos.getX() == this.x && pos.getY() == this.y && pos.getZ() == this.z; + public boolean isInGoal(int x, int y, int z) { + return x == this.x && y == this.y && z == this.z; } @Override - public double heuristic(BlockPos pos) { - int xDiff = pos.getX() - this.x; - int yDiff = pos.getY() - this.y; - int zDiff = pos.getZ() - this.z; + public double heuristic(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; return calculate(xDiff, yDiff, zDiff); } diff --git a/src/main/java/baritone/pathing/goals/GoalComposite.java b/src/api/java/baritone/api/pathing/goals/GoalComposite.java similarity index 80% rename from src/main/java/baritone/pathing/goals/GoalComposite.java rename to src/api/java/baritone/api/pathing/goals/GoalComposite.java index 12de4d93..2926b852 100644 --- a/src/main/java/baritone/pathing/goals/GoalComposite.java +++ b/src/api/java/baritone/api/pathing/goals/GoalComposite.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; import net.minecraft.util.math.BlockPos; @@ -49,15 +49,21 @@ public class GoalComposite implements Goal { } @Override - public boolean isInGoal(BlockPos pos) { - return Arrays.stream(this.goals).anyMatch(goal -> goal.isInGoal(pos)); + public boolean isInGoal(int x, int y, int z) { + for (Goal goal : goals) { + if (goal.isInGoal(x, y, z)) { + return true; + } + } + return false; } @Override - public double heuristic(BlockPos pos) { + public double heuristic(int x, int y, int z) { double min = Double.MAX_VALUE; for (Goal g : goals) { - min = Math.min(min, g.heuristic(pos)); // whichever is closest + // TODO technically this isn't admissible...? + min = Math.min(min, g.heuristic(x, y, z)); // whichever is closest } return min; } diff --git a/src/main/java/baritone/pathing/goals/GoalGetToBlock.java b/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java similarity index 75% rename from src/main/java/baritone/pathing/goals/GoalGetToBlock.java rename to src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java index 5acca96c..959b6fcc 100644 --- a/src/main/java/baritone/pathing/goals/GoalGetToBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalGetToBlock.java @@ -15,10 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.utils.interfaces.IGoalRenderPos; -import baritone.utils.pathing.BetterBlockPos; +import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; @@ -41,14 +40,14 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos { @Override public BlockPos getGoalPos() { - return new BetterBlockPos(x, y, z); + return new BlockPos(x, y, z); } @Override - public boolean isInGoal(BlockPos pos) { - int xDiff = pos.getX() - this.x; - int yDiff = pos.getY() - this.y; - int zDiff = pos.getZ() - this.z; + public boolean isInGoal(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; if (yDiff < 0) { yDiff++; } @@ -56,10 +55,10 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos { } @Override - public double heuristic(BlockPos pos) { - int xDiff = pos.getX() - this.x; - int yDiff = pos.getY() - this.y; - int zDiff = pos.getZ() - this.z; + public double heuristic(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; return GoalBlock.calculate(xDiff, yDiff, zDiff); } diff --git a/src/main/java/baritone/pathing/goals/GoalNear.java b/src/api/java/baritone/api/pathing/goals/GoalNear.java similarity index 74% rename from src/main/java/baritone/pathing/goals/GoalNear.java rename to src/api/java/baritone/api/pathing/goals/GoalNear.java index 11c6cd3f..6befda6b 100644 --- a/src/main/java/baritone/pathing/goals/GoalNear.java +++ b/src/api/java/baritone/api/pathing/goals/GoalNear.java @@ -15,9 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.utils.interfaces.IGoalRenderPos; +import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; public class GoalNear implements Goal, IGoalRenderPos { @@ -34,19 +34,19 @@ public class GoalNear implements Goal, IGoalRenderPos { } @Override - public boolean isInGoal(BlockPos pos) { - int diffX = x - pos.getX(); - int diffY = y - pos.getY(); - int diffZ = z - pos.getZ(); - return diffX * diffX + diffY * diffY + diffZ * diffZ <= rangeSq; + public boolean isInGoal(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; + return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff <= rangeSq; } @Override - public double heuristic(BlockPos pos) { - int diffX = x - pos.getX(); - int diffY = y - pos.getY(); - int diffZ = z - pos.getZ(); - return GoalBlock.calculate(diffX, diffY, diffZ); + public double heuristic(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; + return GoalBlock.calculate(xDiff, yDiff, zDiff); } @Override diff --git a/src/main/java/baritone/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java similarity index 83% rename from src/main/java/baritone/pathing/goals/GoalRunAway.java rename to src/api/java/baritone/api/pathing/goals/GoalRunAway.java index 0ad49faf..cb7a000e 100644 --- a/src/main/java/baritone/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; import net.minecraft.util.math.BlockPos; @@ -41,10 +41,10 @@ public class GoalRunAway implements Goal { } @Override - public boolean isInGoal(BlockPos pos) { + public boolean isInGoal(int x, int y, int z) { for (BlockPos p : from) { - int diffX = pos.getX() - p.getX(); - int diffZ = pos.getZ() - p.getZ(); + int diffX = x - p.getX(); + int diffZ = z - p.getZ(); double distSq = diffX * diffX + diffZ * diffZ; if (distSq < distanceSq) { return false; @@ -54,10 +54,10 @@ public class GoalRunAway implements Goal { } @Override - public double heuristic(BlockPos pos) {//mostly copied from GoalBlock + public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock double min = Double.MAX_VALUE; for (BlockPos p : from) { - double h = GoalXZ.calculate(p.getX() - pos.getX(), p.getZ() - pos.getZ()); + double h = GoalXZ.calculate(p.getX() - x, p.getZ() - z); if (h < min) { min = h; } diff --git a/src/main/java/baritone/pathing/goals/GoalTwoBlocks.java b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java similarity index 81% rename from src/main/java/baritone/pathing/goals/GoalTwoBlocks.java rename to src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java index 44a33425..4ed1bf5e 100644 --- a/src/main/java/baritone/pathing/goals/GoalTwoBlocks.java +++ b/src/api/java/baritone/api/pathing/goals/GoalTwoBlocks.java @@ -15,9 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.utils.interfaces.IGoalRenderPos; +import baritone.api.utils.interfaces.IGoalRenderPos; import net.minecraft.util.math.BlockPos; /** @@ -54,18 +54,18 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos { } @Override - public boolean isInGoal(BlockPos pos) { - return pos.getX() == this.x && (pos.getY() == this.y || pos.getY() == this.y - 1) && pos.getZ() == this.z; + public boolean isInGoal(int x, int y, int z) { + return x == this.x && (y == this.y || y == this.y - 1) && z == this.z; } @Override - public double heuristic(BlockPos pos) { - double xDiff = pos.getX() - this.x; - int yDiff = pos.getY() - this.y; + public double heuristic(int x, int y, int z) { + int xDiff = x - this.x; + int yDiff = y - this.y; + int zDiff = z - this.z; if (yDiff < 0) { yDiff++; } - double zDiff = pos.getZ() - this.z; return GoalBlock.calculate(xDiff, yDiff, zDiff); } diff --git a/src/main/java/baritone/pathing/goals/GoalXZ.java b/src/api/java/baritone/api/pathing/goals/GoalXZ.java similarity index 82% rename from src/main/java/baritone/pathing/goals/GoalXZ.java rename to src/api/java/baritone/api/pathing/goals/GoalXZ.java index 3362149c..636c649f 100644 --- a/src/main/java/baritone/pathing/goals/GoalXZ.java +++ b/src/api/java/baritone/api/pathing/goals/GoalXZ.java @@ -15,11 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import baritone.Baritone; -import baritone.utils.Utils; -import net.minecraft.util.math.BlockPos; +import baritone.api.BaritoneAPI; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -48,14 +46,14 @@ public class GoalXZ implements Goal { } @Override - public boolean isInGoal(BlockPos pos) { - return pos.getX() == x && pos.getZ() == z; + public boolean isInGoal(int x, int y, int z) { + return x == this.x && z == this.z; } @Override - public double heuristic(BlockPos pos) {//mostly copied from GoalBlock - double xDiff = pos.getX() - this.x; - double zDiff = pos.getZ() - this.z; + public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock + int xDiff = x - this.x; + int zDiff = z - this.z; return calculate(xDiff, zDiff); } @@ -82,11 +80,11 @@ public class GoalXZ implements Goal { diagonal = z; } diagonal *= SQRT_2; - return (diagonal + straight) * Baritone.settings().costHeuristic.get(); // big TODO tune + return (diagonal + straight) * BaritoneAPI.getSettings().costHeuristic.get(); // big TODO tune } public static GoalXZ fromDirection(Vec3d origin, float yaw, double distance) { - float theta = (float) Utils.degToRad(yaw); + float theta = (float) Math.toRadians(yaw); double x = origin.x - MathHelper.sin(theta) * distance; double z = origin.z + MathHelper.cos(theta) * distance; return new GoalXZ((int) x, (int) z); diff --git a/src/main/java/baritone/pathing/goals/GoalYLevel.java b/src/api/java/baritone/api/pathing/goals/GoalYLevel.java similarity index 82% rename from src/main/java/baritone/pathing/goals/GoalYLevel.java rename to src/api/java/baritone/api/pathing/goals/GoalYLevel.java index f90161d2..ce54eebb 100644 --- a/src/main/java/baritone/pathing/goals/GoalYLevel.java +++ b/src/api/java/baritone/api/pathing/goals/GoalYLevel.java @@ -15,16 +15,16 @@ * along with Baritone. If not, see . */ -package baritone.pathing.goals; +package baritone.api.pathing.goals; -import net.minecraft.util.math.BlockPos; +import baritone.api.pathing.movement.ActionCosts; /** * Useful for mining (getting to diamond / iron level) * * @author leijurv */ -public class GoalYLevel implements Goal { +public class GoalYLevel implements Goal, ActionCosts { /** * The target Y level @@ -36,13 +36,13 @@ public class GoalYLevel implements Goal { } @Override - public boolean isInGoal(BlockPos pos) { - return pos.getY() == level; + public boolean isInGoal(int x, int y, int z) { + return y == level; } @Override - public double heuristic(BlockPos pos) { - return calculate(level, pos.getY()); + public double heuristic(int x, int y, int z) { + return calculate(level, y); } public static double calculate(int goalY, int currentY) { diff --git a/src/main/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.java b/src/api/java/baritone/api/pathing/movement/ActionCosts.java similarity index 70% rename from src/main/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.java rename to src/api/java/baritone/api/pathing/movement/ActionCosts.java index fe589d6f..e1f72dfa 100644 --- a/src/main/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.java +++ b/src/api/java/baritone/api/pathing/movement/ActionCosts.java @@ -15,9 +15,36 @@ * along with Baritone. If not, see . */ -package baritone.pathing.movement; +package baritone.api.pathing.movement; + +public interface ActionCosts { + + /** + * These costs are measured roughly in ticks btw + */ + double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633 + double WALK_ONE_IN_WATER_COST = 20 / 2.2; + double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_BLOCK_COST * 2; // 0.4 in BlockSoulSand but effectively about half + double SPRINT_ONE_OVER_SOUL_SAND_COST = WALK_ONE_OVER_SOUL_SAND_COST * 0.75; + double LADDER_UP_ONE_COST = 20 / 2.35; + double LADDER_DOWN_ONE_COST = 20 / 3.0; + double SNEAK_ONE_BLOCK_COST = 20 / 1.3; + double SPRINT_ONE_BLOCK_COST = 20 / 5.612; // 3.564 + /** + * To walk off an edge you need to walk 0.5 to the edge then 0.3 to start falling off + */ + double WALK_OFF_BLOCK_COST = WALK_ONE_BLOCK_COST * 0.8; + /** + * To walk the rest of the way to be centered on the new block + */ + double CENTER_AFTER_FALL_COST = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST; + + /** + * don't make this Double.MAX_VALUE because it's added to other things, maybe other COST_INFs, + * and that would make it overflow to negative + */ + double COST_INF = 1000000; -public interface ActionCostsButOnlyTheOnesThatMakeMickeyDieInside { double[] FALL_N_BLOCKS_COST = generateFallNBlocksCost(); double FALL_1_25_BLOCKS_COST = distanceToTicks(1.25); diff --git a/src/main/java/baritone/utils/Rotation.java b/src/api/java/baritone/api/utils/Logger.java similarity index 78% rename from src/main/java/baritone/utils/Rotation.java rename to src/api/java/baritone/api/utils/Logger.java index ce92d009..c2f6c99a 100644 --- a/src/main/java/baritone/utils/Rotation.java +++ b/src/api/java/baritone/api/utils/Logger.java @@ -15,13 +15,13 @@ * along with Baritone. If not, see . */ -package baritone.utils; +package baritone.api.utils; -import net.minecraft.util.Tuple; +/** + * @author Brady + * @since 9/23/2018 + */ +public class Logger { -public class Rotation extends Tuple { - public Rotation(Float yaw, Float pitch) { - super(yaw, pitch); - } } diff --git a/src/api/java/baritone/api/utils/Rotation.java b/src/api/java/baritone/api/utils/Rotation.java new file mode 100644 index 00000000..dc697169 --- /dev/null +++ b/src/api/java/baritone/api/utils/Rotation.java @@ -0,0 +1,112 @@ +/* + * 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; + +/** + * @author Brady + * @since 9/25/2018 + */ +public class Rotation { + + /** + * The yaw angle of this Rotation + */ + private float yaw; + + /** + * The pitch angle of this Rotation + */ + private float pitch; + + public Rotation(float yaw, float pitch) { + this.yaw = yaw; + this.pitch = pitch; + } + + /** + * @return The yaw of this rotation + */ + public float getYaw() { + return this.yaw; + } + + /** + * @return The pitch of this rotation + */ + public float getPitch() { + return this.pitch; + } + + /** + * Adds the yaw/pitch of the specified rotations to this + * rotation's yaw/pitch, and returns the result. + * + * @param other Another rotation + * @return The result from adding the other rotation to this rotation + */ + public Rotation add(Rotation other) { + return new Rotation( + this.yaw + other.yaw, + this.pitch + other.pitch + ); + } + + /** + * Subtracts the yaw/pitch of the specified rotations from this + * rotation's yaw/pitch, and returns the result. + * + * @param other Another rotation + * @return The result from subtracting the other rotation from this rotation + */ + public Rotation subtract(Rotation other) { + return new Rotation( + this.yaw - other.yaw, + this.pitch - other.pitch + ); + } + + /** + * @return A copy of this rotation with the pitch clamped + */ + public Rotation clamp() { + return new Rotation( + this.yaw, + RotationUtils.clampPitch(this.pitch) + ); + } + + /** + * @return A copy of this rotation with the yaw normalized + */ + public Rotation normalize() { + return new Rotation( + RotationUtils.normalizeYaw(this.yaw), + this.pitch + ); + } + + /** + * @return A copy of this rotation with the pitch clamped and the yaw normalized + */ + public Rotation normalizeAndClamp() { + return new Rotation( + RotationUtils.normalizeYaw(this.yaw), + RotationUtils.clampPitch(this.pitch) + ); + } +} diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java new file mode 100644 index 00000000..0df4b38d --- /dev/null +++ b/src/api/java/baritone/api/utils/RotationUtils.java @@ -0,0 +1,54 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.utils; + +/** + * @author Brady + * @since 9/25/2018 + */ +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; + } +} diff --git a/src/main/java/baritone/utils/interfaces/IGoalRenderPos.java b/src/api/java/baritone/api/utils/interfaces/IGoalRenderPos.java similarity index 95% rename from src/main/java/baritone/utils/interfaces/IGoalRenderPos.java rename to src/api/java/baritone/api/utils/interfaces/IGoalRenderPos.java index aa4ffa78..5bbbc007 100644 --- a/src/main/java/baritone/utils/interfaces/IGoalRenderPos.java +++ b/src/api/java/baritone/api/utils/interfaces/IGoalRenderPos.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.utils.interfaces; +package baritone.api.utils.interfaces; import net.minecraft.util.math.BlockPos; diff --git a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java index d5d41f44..2f0d1ab4 100644 --- a/src/launch/java/baritone/launch/mixins/MixinMinecraft.java +++ b/src/launch/java/baritone/launch/mixins/MixinMinecraft.java @@ -23,6 +23,7 @@ import baritone.api.event.events.TickEvent; import baritone.api.event.events.WorldEvent; import baritone.api.event.events.type.EventState; import baritone.behavior.PathingBehavior; +import baritone.utils.BaritoneAutoTest; import baritone.utils.ExampleBaritoneControl; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; @@ -39,6 +40,7 @@ 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; /** @@ -59,11 +61,22 @@ public class MixinMinecraft { method = "init", at = @At("RETURN") ) - private void init(CallbackInfo ci) { + private void postInit(CallbackInfo ci) { Baritone.INSTANCE.init(); ExampleBaritoneControl.INSTANCE.initAndRegister(); } + @Inject( + method = "init", + at = @At( + value = "INVOKE", + target = "net/minecraft/client/Minecraft.startTimerHackThread()V" + ) + ) + private void preInit(CallbackInfo ci) { + BaritoneAutoTest.INSTANCE.onPreInit(); + } + @Inject( method = "runTick", at = @At( diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index 06bf365a..51e7598a 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -17,10 +17,13 @@ package baritone; -import baritone.api.behavior.Behavior; +import baritone.api.BaritoneAPI; +import baritone.api.Settings; import baritone.api.event.listener.IGameEventListener; import baritone.behavior.*; +import baritone.cache.WorldProvider; import baritone.event.GameEventHandler; +import baritone.utils.BaritoneAutoTest; import baritone.utils.InputOverrideHandler; import net.minecraft.client.Minecraft; @@ -80,7 +83,13 @@ public enum Baritone { this.threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); this.gameEventHandler = new GameEventHandler(); this.inputOverrideHandler = new InputOverrideHandler(); - this.settings = new Settings(); + + // Acquire the "singleton" instance of the settings directly from the API + // We might want to change this... + this.settings = BaritoneAPI.getSettings(); + + BaritoneAPI.registerProviders(WorldProvider.INSTANCE); + this.behaviors = new ArrayList<>(); { registerBehavior(PathingBehavior.INSTANCE); @@ -89,6 +98,19 @@ public enum Baritone { registerBehavior(LocationTrackingBehavior.INSTANCE); registerBehavior(FollowBehavior.INSTANCE); registerBehavior(MineBehavior.INSTANCE); + + // TODO: Clean this up + // Maybe combine this call in someway with the registerBehavior calls? + BaritoneAPI.registerDefaultBehaviors( + FollowBehavior.INSTANCE, + LookBehavior.INSTANCE, + MemoryBehavior.INSTANCE, + MineBehavior.INSTANCE, + PathingBehavior.INSTANCE + ); + } + if (BaritoneAutoTest.ENABLE_AUTO_TEST && "true".equals(System.getenv("BARITONE_AUTO_TEST"))) { + registerEventListener(BaritoneAutoTest.INSTANCE); } this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone"); if (!Files.exists(dir.toPath())) { diff --git a/src/api/java/baritone/api/behavior/Behavior.java b/src/main/java/baritone/behavior/Behavior.java similarity index 88% rename from src/api/java/baritone/api/behavior/Behavior.java rename to src/main/java/baritone/behavior/Behavior.java index 872ce1bd..b856e423 100644 --- a/src/api/java/baritone/api/behavior/Behavior.java +++ b/src/main/java/baritone/behavior/Behavior.java @@ -15,10 +15,9 @@ * along with Baritone. If not, see . */ -package baritone.api.behavior; +package baritone.behavior; -import baritone.api.event.listener.AbstractGameEventListener; -import baritone.api.utils.interfaces.Toggleable; +import baritone.api.behavior.IBehavior; /** * A type of game event listener that can be toggled. @@ -26,7 +25,7 @@ import baritone.api.utils.interfaces.Toggleable; * @author Brady * @since 8/1/2018 6:29 PM */ -public class Behavior implements AbstractGameEventListener, Toggleable { +public class Behavior implements IBehavior { /** * Whether or not this behavior is enabled diff --git a/src/main/java/baritone/behavior/FollowBehavior.java b/src/main/java/baritone/behavior/FollowBehavior.java index 21ebbbea..83ca5135 100644 --- a/src/main/java/baritone/behavior/FollowBehavior.java +++ b/src/main/java/baritone/behavior/FollowBehavior.java @@ -18,10 +18,10 @@ package baritone.behavior; import baritone.Baritone; -import baritone.api.behavior.Behavior; +import baritone.api.behavior.IFollowBehavior; import baritone.api.event.events.TickEvent; -import baritone.pathing.goals.GoalNear; -import baritone.pathing.goals.GoalXZ; +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; @@ -31,7 +31,7 @@ import net.minecraft.util.math.BlockPos; * * @author leijurv */ -public final class FollowBehavior extends Behavior implements Helper { +public final class FollowBehavior extends Behavior implements IFollowBehavior, Helper { public static final FollowBehavior INSTANCE = new FollowBehavior(); @@ -42,6 +42,7 @@ public final class FollowBehavior extends Behavior implements Helper { @Override public void onTick(TickEvent event) { if (event.getType() == TickEvent.Type.OUT) { + following = null; return; } if (following == null) { @@ -60,14 +61,17 @@ public final class FollowBehavior extends Behavior implements Helper { PathingBehavior.INSTANCE.path(); } + @Override public void follow(Entity entity) { this.following = entity; } + @Override public Entity following() { return this.following; } + @Override public void cancel() { PathingBehavior.INSTANCE.cancel(); follow(null); diff --git a/src/main/java/baritone/behavior/LocationTrackingBehavior.java b/src/main/java/baritone/behavior/LocationTrackingBehavior.java index e48e482e..dee74e79 100644 --- a/src/main/java/baritone/behavior/LocationTrackingBehavior.java +++ b/src/main/java/baritone/behavior/LocationTrackingBehavior.java @@ -17,10 +17,9 @@ package baritone.behavior; -import baritone.api.behavior.Behavior; +import baritone.api.event.events.BlockInteractEvent; import baritone.cache.Waypoint; import baritone.cache.WorldProvider; -import baritone.api.event.events.BlockInteractEvent; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import net.minecraft.block.BlockBed; @@ -43,12 +42,12 @@ public final class LocationTrackingBehavior extends Behavior implements Helper { @Override public void onBlockInteract(BlockInteractEvent event) { if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(event.getPos()) instanceof BlockBed) { - WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos())); + WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos())); } } @Override public void onPlayerDeath() { - WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet())); + WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet())); } } diff --git a/src/main/java/baritone/behavior/LookBehavior.java b/src/main/java/baritone/behavior/LookBehavior.java index d45ad585..a42a1e50 100644 --- a/src/main/java/baritone/behavior/LookBehavior.java +++ b/src/main/java/baritone/behavior/LookBehavior.java @@ -18,14 +18,14 @@ package baritone.behavior; import baritone.Baritone; -import baritone.Settings; -import baritone.api.behavior.Behavior; +import baritone.api.Settings; +import baritone.api.behavior.ILookBehavior; import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.RotationMoveEvent; +import baritone.api.utils.Rotation; import baritone.utils.Helper; -import baritone.utils.Rotation; -public final class LookBehavior extends Behavior implements Helper { +public final class LookBehavior extends Behavior implements ILookBehavior, Helper { public static final LookBehavior INSTANCE = new LookBehavior(); @@ -51,6 +51,7 @@ public final class LookBehavior extends Behavior implements Helper { private LookBehavior() {} + @Override public void updateTarget(Rotation target, boolean force) { this.target = target; this.force = force || !Baritone.settings().freeLook.get(); @@ -68,9 +69,9 @@ public final class LookBehavior extends Behavior implements Helper { switch (event.getState()) { case PRE: { if (this.force) { - player().rotationYaw = this.target.getFirst(); + player().rotationYaw = this.target.getYaw(); float oldPitch = player().rotationPitch; - float desiredPitch = this.target.getSecond(); + float desiredPitch = this.target.getPitch(); player().rotationPitch = desiredPitch; if (desiredPitch == oldPitch) { nudgeToLevel(); @@ -78,7 +79,7 @@ public final class LookBehavior extends Behavior implements Helper { this.target = null; } else if (silent) { this.lastYaw = player().rotationYaw; - player().rotationYaw = this.target.getFirst(); + player().rotationYaw = this.target.getYaw(); } break; } @@ -92,7 +93,6 @@ public final class LookBehavior extends Behavior implements Helper { default: break; } - new Thread().start(); } @Override @@ -101,7 +101,7 @@ public final class LookBehavior extends Behavior implements Helper { switch (event.getState()) { case PRE: this.lastYaw = player().rotationYaw; - player().rotationYaw = this.target.getFirst(); + player().rotationYaw = this.target.getYaw(); break; case POST: player().rotationYaw = this.lastYaw; diff --git a/src/main/java/baritone/behavior/LookBehaviorUtils.java b/src/main/java/baritone/behavior/LookBehaviorUtils.java index ed7f730e..8cbe01ab 100644 --- a/src/main/java/baritone/behavior/LookBehaviorUtils.java +++ b/src/main/java/baritone/behavior/LookBehaviorUtils.java @@ -17,7 +17,11 @@ package baritone.behavior; -import baritone.utils.*; +import baritone.api.utils.Rotation; +import baritone.utils.BlockStateInterface; +import baritone.utils.Helper; +import baritone.utils.RayTraceUtils; +import baritone.utils.Utils; import net.minecraft.block.BlockFire; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.*; @@ -47,10 +51,10 @@ public final class LookBehaviorUtils implements Helper { * @return vector of the rotation */ public static Vec3d calcVec3dFromRotation(Rotation rotation) { - float f = MathHelper.cos(-rotation.getFirst() * (float) DEG_TO_RAD - (float) Math.PI); - float f1 = MathHelper.sin(-rotation.getFirst() * (float) DEG_TO_RAD - (float) Math.PI); - float f2 = -MathHelper.cos(-rotation.getSecond() * (float) DEG_TO_RAD); - float f3 = MathHelper.sin(-rotation.getSecond() * (float) DEG_TO_RAD); + float f = MathHelper.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI); + float f1 = MathHelper.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI); + float f2 = -MathHelper.cos(-rotation.getPitch() * (float) DEG_TO_RAD); + float f3 = MathHelper.sin(-rotation.getPitch() * (float) DEG_TO_RAD); return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2)); } diff --git a/src/main/java/baritone/behavior/MemoryBehavior.java b/src/main/java/baritone/behavior/MemoryBehavior.java index c850c8e5..b0980322 100644 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ b/src/main/java/baritone/behavior/MemoryBehavior.java @@ -17,7 +17,8 @@ package baritone.behavior; -import baritone.api.behavior.Behavior; +import baritone.api.behavior.IMemoryBehavior; +import baritone.api.behavior.memory.IRememberedInventory; import baritone.api.event.events.PacketEvent; import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.type.EventState; @@ -38,7 +39,7 @@ import java.util.*; * @author Brady * @since 8/6/2018 9:47 PM */ -public final class MemoryBehavior extends Behavior implements Helper { +public final class MemoryBehavior extends Behavior implements IMemoryBehavior, Helper { public static MemoryBehavior INSTANCE = new MemoryBehavior(); @@ -128,6 +129,7 @@ public final class MemoryBehavior extends Behavior implements Helper { }); } + @Override public final RememberedInventory getInventoryByPos(BlockPos pos) { return this.rememberedInventories.get(pos); } @@ -170,7 +172,7 @@ public final class MemoryBehavior extends Behavior implements Helper { *

* Associated with a {@link BlockPos} in {@link MemoryBehavior#rememberedInventories}. */ - public static class RememberedInventory { + public static class RememberedInventory implements IRememberedInventory { /** * The list of items in the inventory @@ -191,11 +193,14 @@ public final class MemoryBehavior extends Behavior implements Helper { this.items = new ArrayList<>(); } - /** - * @return The list of items in the inventory - */ - public final List getItems() { + @Override + public final List getContents() { return this.items; } + + @Override + public final int getSize() { + return this.size; + } } } diff --git a/src/main/java/baritone/behavior/MineBehavior.java b/src/main/java/baritone/behavior/MineBehavior.java index 3073c0f8..0f1a6b34 100644 --- a/src/main/java/baritone/behavior/MineBehavior.java +++ b/src/main/java/baritone/behavior/MineBehavior.java @@ -18,17 +18,17 @@ package baritone.behavior; import baritone.Baritone; -import baritone.api.behavior.Behavior; +import baritone.api.behavior.IMineBehavior; import baritone.api.event.events.PathEvent; import baritone.api.event.events.TickEvent; +import baritone.api.pathing.goals.Goal; import baritone.cache.CachedChunk; import baritone.cache.ChunkPacker; import baritone.cache.WorldProvider; import baritone.cache.WorldScanner; -import baritone.pathing.goals.Goal; -import baritone.pathing.goals.GoalBlock; -import baritone.pathing.goals.GoalComposite; -import baritone.pathing.goals.GoalTwoBlocks; +import baritone.api.pathing.goals.GoalBlock; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.pathing.goals.GoalTwoBlocks; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import net.minecraft.block.Block; @@ -46,7 +46,7 @@ import java.util.stream.Collectors; * * @author leijurv */ -public final class MineBehavior extends Behavior implements Helper { +public final class MineBehavior extends Behavior implements IMineBehavior, Helper { public static final MineBehavior INSTANCE = new MineBehavior(); @@ -58,6 +58,10 @@ public final class MineBehavior extends Behavior implements Helper { @Override public void onTick(TickEvent event) { + if (event.getType() == TickEvent.Type.OUT) { + cancel(); + return; + } if (mining == null) { return; } @@ -74,7 +78,7 @@ public final class MineBehavior extends Behavior implements Helper { int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); if (mineGoalUpdateInterval != 0) { if (event.getCount() % mineGoalUpdateInterval == 0) { - updateGoal(); + Baritone.INSTANCE.getExecutor().execute(this::updateGoal); } } PathingBehavior.INSTANCE.revalidateGoal(); @@ -105,7 +109,7 @@ public final class MineBehavior extends Behavior implements Helper { PathingBehavior.INSTANCE.path(); } - public static GoalComposite coalesce(List locs) { + public GoalComposite coalesce(List locs) { return new GoalComposite(locs.stream().map(loc -> { if (!Baritone.settings().forceInternalMining.get()) { return new GoalTwoBlocks(loc); @@ -129,13 +133,13 @@ public final class MineBehavior extends Behavior implements Helper { }).toArray(Goal[]::new)); } - public static List scanFor(List mining, int max) { + public List scanFor(List mining, int max) { 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().cache.getLocationsOf(ChunkPacker.blockToString(m), 1, 1)); + locs.addAll(WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), 1, 1)); } else { uninteresting.add(m); } @@ -152,7 +156,7 @@ public final class MineBehavior extends Behavior implements Helper { return prune(locs, mining, max); } - public static List prune(List locs, List mining, int max) { + public List prune(List locs, List mining, int max) { BlockPos playerFeet = MineBehavior.INSTANCE.playerFeet(); locs.sort(Comparator.comparingDouble(playerFeet::distanceSq)); @@ -167,6 +171,7 @@ public final class MineBehavior extends Behavior implements Helper { return locs; } + @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.quantity = quantity; @@ -174,12 +179,15 @@ public final class MineBehavior extends Behavior implements Helper { updateGoal(); } - public void mine(Block... blocks) { + @Override + public void mine(int quantity, Block... blocks) { this.mining = blocks == null || blocks.length == 0 ? null : Arrays.asList(blocks); + this.quantity = quantity; this.locationsCache = new ArrayList<>(); updateGoal(); } + @Override public void cancel() { mine(0, (String[]) null); PathingBehavior.INSTANCE.cancel(); diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 4a36ce73..99120ce8 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -18,33 +18,36 @@ package baritone.behavior; import baritone.Baritone; -import baritone.api.behavior.Behavior; +import baritone.api.behavior.IPathingBehavior; import baritone.api.event.events.PathEvent; import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.RenderEvent; import baritone.api.event.events.TickEvent; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalXZ; +import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.pathing.calc.AStarPathFinder; import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.IPathFinder; -import baritone.pathing.goals.Goal; -import baritone.pathing.goals.GoalXZ; import baritone.pathing.movement.MovementHelper; import baritone.pathing.path.IPath; import baritone.pathing.path.PathExecutor; +import baritone.utils.BlockBreakHelper; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import baritone.utils.PathRenderer; -import baritone.utils.interfaces.IGoalRenderPos; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.EmptyChunk; -import java.awt.*; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Optional; +import java.util.stream.Collectors; -public final class PathingBehavior extends Behavior implements Helper { +public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper { public static final PathingBehavior INSTANCE = new PathingBehavior(); @@ -170,6 +173,7 @@ public final class PathingBehavior extends Behavior implements Helper { } } + @Override public Optional ticksRemainingInSegment() { if (current == null) { return Optional.empty(); @@ -177,10 +181,12 @@ public final class PathingBehavior extends Behavior implements Helper { return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition())); } + @Override public void setGoal(Goal goal) { this.goal = goal; } + @Override public Goal getGoal() { return goal; } @@ -193,16 +199,30 @@ public final class PathingBehavior extends Behavior implements Helper { return next; } + // TODO: Expose this method in the API? + // In order to do so, we'd need to move over IPath which has a whole lot of references to other + // things that may not need to be exposed necessarily, so we'll need to figure that out. public Optional getPath() { return Optional.ofNullable(current).map(PathExecutor::getPath); } + @Override + public boolean isPathing() { + return this.current != null; + } + + @Override public void cancel() { dispatchPathEvent(PathEvent.CANCELED); current = null; next = null; Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel); + BlockBreakHelper.stopBreakingBlock(); + } + + public void forceCancel() { // NOT exposed on public api + isPathCalcInProgress = false; } /** @@ -210,6 +230,7 @@ public final class PathingBehavior extends Behavior implements Helper { * * @return true if this call started path calculation, false if it was already calculating or executing a path */ + @Override public boolean path() { if (goal == null) { return false; @@ -232,7 +253,10 @@ public final class PathingBehavior extends Behavior implements Helper { } } - public BlockPos pathStart() { + /** + * @return The starting {@link BlockPos} for a new path + */ + private BlockPos pathStart() { BetterBlockPos feet = playerFeet(); if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR) && MovementHelper.canWalkOn(feet.down().down())) { return feet.down(); @@ -246,7 +270,8 @@ public final class PathingBehavior extends Behavior implements Helper { * @param start * @param talkAboutIt */ - private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, final Optional previous) { + private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, + final Optional previous) { synchronized (pathCalcLock) { if (isPathCalcInProgress) { throw new IllegalStateException("Already doing it"); @@ -329,8 +354,9 @@ public final class PathingBehavior extends Behavior implements Helper { } else { timeout = Baritone.settings().planAheadTimeoutMS.get(); } + Optional> favoredPositions = previous.map(IPath::positions).map(Collection::stream).map(x -> x.map(y -> y.hashCode)).map(x -> x.collect(Collectors.toList())).map(HashSet::new); // <-- okay this is EPIC try { - IPathFinder pf = new AStarPathFinder(start, goal, previous.map(IPath::positions)); + IPathFinder pf = new AStarPathFinder(start, goal, favoredPositions); return pf.calculate(timeout); } catch (Exception e) { logDebug("Pathing exception: " + e); @@ -361,7 +387,7 @@ public final class PathingBehavior extends Behavior implements Helper { // System.out.println(event.getPartialTicks()); float partialTicks = event.getPartialTicks(); if (goal != null && Baritone.settings().renderGoal.value) { - PathRenderer.drawLitDankGoalBox(player(), goal, partialTicks, Color.GREEN); + PathRenderer.drawLitDankGoalBox(player(), goal, partialTicks, Baritone.settings().colorGoalBox.get()); } if (!Baritone.settings().renderPath.get()) { return; @@ -378,27 +404,27 @@ public final class PathingBehavior extends Behavior implements Helper { // Render the current path, if there is one if (current != null && current.getPath() != null) { int renderBegin = Math.max(current.getPosition() - 3, 0); - PathRenderer.drawPath(current.getPath(), renderBegin, player(), partialTicks, Color.RED, Baritone.settings().fadePath.get(), 10, 20); + PathRenderer.drawPath(current.getPath(), renderBegin, player(), partialTicks, Baritone.settings().colorCurrentPath.get(), Baritone.settings().fadePath.get(), 10, 20); } if (next != null && next.getPath() != null) { - PathRenderer.drawPath(next.getPath(), 0, player(), partialTicks, Color.MAGENTA, Baritone.settings().fadePath.get(), 10, 20); + PathRenderer.drawPath(next.getPath(), 0, player(), partialTicks, Baritone.settings().colorNextPath.get(), Baritone.settings().fadePath.get(), 10, 20); } //long split = System.nanoTime(); if (current != null) { - PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Color.RED); - PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Color.GREEN); - PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Color.MAGENTA); + PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get()); + PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get()); + PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get()); } // If there is a path calculation currently running, render the path calculation process AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> { currentlyRunning.bestPathSoFar().ifPresent(p -> { - PathRenderer.drawPath(p, 0, player(), partialTicks, Color.BLUE, Baritone.settings().fadePath.get(), 10, 20); + PathRenderer.drawPath(p, 0, player(), partialTicks, Baritone.settings().colorBestPathSoFar.get(), Baritone.settings().fadePath.get(), 10, 20); currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> { - PathRenderer.drawPath(mr, 0, player(), partialTicks, Color.CYAN, Baritone.settings().fadePath.get(), 10, 20); - PathRenderer.drawManySelectionBoxes(player(), Collections.singletonList(mr.getDest()), partialTicks, Color.CYAN); + PathRenderer.drawPath(mr, 0, player(), partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20); + PathRenderer.drawManySelectionBoxes(player(), Collections.singletonList(mr.getDest()), partialTicks, Baritone.settings().colorMostRecentConsidered.get()); }); }); }); @@ -408,4 +434,9 @@ public final class PathingBehavior extends Behavior implements Helper { // System.out.println("Frame took " + (split - start) + " " + (end - split)); //} } + + @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 fbdd42f7..b8d88a49 100644 --- a/src/main/java/baritone/cache/CachedChunk.java +++ b/src/main/java/baritone/cache/CachedChunk.java @@ -17,7 +17,8 @@ package baritone.cache; -import baritone.utils.pathing.IBlockTypeAccess; +import baritone.api.cache.IBlockTypeAccess; +import baritone.utils.Helper; import baritone.utils.pathing.PathingBlockType; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; @@ -30,7 +31,7 @@ import java.util.*; * @author Brady * @since 8/3/2018 1:04 AM */ -public final class CachedChunk implements IBlockTypeAccess { +public final class CachedChunk implements IBlockTypeAccess, Helper { public static final Set BLOCKS_TO_KEEP_TRACK_OF = Collections.unmodifiableSet(new HashSet() {{ add(Blocks.DIAMOND_ORE); @@ -99,13 +100,13 @@ public final class CachedChunk implements IBlockTypeAccess { /** * The block names of each surface level block for generating an overview */ - private final String[] overview; + private final IBlockState[] overview; private final int[] heightMap; private final Map> specialBlockLocations; - CachedChunk(int x, int z, BitSet data, String[] overview, Map> specialBlockLocations) { + CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map> specialBlockLocations) { validateSize(data); this.x = x; @@ -122,12 +123,11 @@ public final class CachedChunk implements IBlockTypeAccess { int internalPos = z << 4 | x; if (heightMap[internalPos] == y) { // we have this exact block, it's a surface block - IBlockState state = ChunkPacker.stringToBlock(overview[internalPos]).getDefaultState(); /*System.out.println("Saying that " + x + "," + y + "," + z + " is " + state); if (!Minecraft.getMinecraft().world.getBlockState(new BlockPos(x + this.x * 16, y, z + this.z * 16)).getBlock().equals(state.getBlock())) { throw new IllegalStateException("failed " + Minecraft.getMinecraft().world.getBlockState(new BlockPos(x + this.x * 16, y, z + this.z * 16)).getBlock() + " " + state.getBlock() + " " + (x + this.x * 16) + " " + y + " " + (z + this.z * 16)); }*/ - return state; + return overview[internalPos]; } PathingBlockType type = getType(x, y, z); if (type == PathingBlockType.SOLID && y == 127 && mc.player.dimension == -1) { @@ -157,7 +157,7 @@ public final class CachedChunk implements IBlockTypeAccess { } } - public final String[] getOverview() { + public final IBlockState[] getOverview() { return overview; } diff --git a/src/main/java/baritone/cache/CachedRegion.java b/src/main/java/baritone/cache/CachedRegion.java index f036f264..e9402bd5 100644 --- a/src/main/java/baritone/cache/CachedRegion.java +++ b/src/main/java/baritone/cache/CachedRegion.java @@ -17,7 +17,7 @@ package baritone.cache; -import baritone.utils.pathing.IBlockTypeAccess; +import baritone.api.cache.ICachedRegion; import net.minecraft.block.state.IBlockState; import net.minecraft.util.math.BlockPos; @@ -33,7 +33,8 @@ import java.util.zip.GZIPOutputStream; * @author Brady * @since 8/3/2018 9:35 PM */ -public final class CachedRegion implements IBlockTypeAccess { +public final class CachedRegion implements ICachedRegion { + private static final byte CHUNK_NOT_PRESENT = 0; private static final byte CHUNK_PRESENT = 1; @@ -77,6 +78,7 @@ public final class CachedRegion implements IBlockTypeAccess { return null; } + @Override public final boolean isCached(int x, int z) { return chunks[x >> 4][z >> 4] != null; } @@ -145,7 +147,7 @@ public final class CachedRegion implements IBlockTypeAccess { for (int x = 0; x < 32; x++) { if (chunks[x][z] != null) { for (int i = 0; i < 256; i++) { - out.writeUTF(chunks[x][z].getOverview()[i]); + out.writeUTF(ChunkPacker.blockToString(chunks[x][z].getOverview()[i].getBlock())); } } } @@ -215,7 +217,7 @@ public final class CachedRegion implements IBlockTypeAccess { int regionZ = this.z; int chunkX = x + 32 * regionX; int chunkZ = z + 32 * regionZ; - tmpCached[x][z] = new CachedChunk(chunkX, chunkZ, BitSet.valueOf(bytes), new String[256], location[x][z]); + tmpCached[x][z] = new CachedChunk(chunkX, chunkZ, BitSet.valueOf(bytes), new IBlockState[256], location[x][z]); break; case CHUNK_NOT_PRESENT: tmpCached[x][z] = null; @@ -229,7 +231,7 @@ public final class CachedRegion implements IBlockTypeAccess { for (int x = 0; x < 32; x++) { if (tmpCached[x][z] != null) { for (int i = 0; i < 256; i++) { - tmpCached[x][z].getOverview()[i] = in.readUTF(); + tmpCached[x][z].getOverview()[i] = ChunkPacker.stringToBlock(in.readUTF()).getDefaultState(); } } } @@ -280,6 +282,7 @@ public final class CachedRegion implements IBlockTypeAccess { /** * @return The region x coordinate */ + @Override public final int getX() { return this.x; } @@ -287,6 +290,7 @@ public final class CachedRegion implements IBlockTypeAccess { /** * @return The region z coordinate */ + @Override public final int getZ() { return this.z; } diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java index 91a70d48..3901303d 100644 --- a/src/main/java/baritone/cache/CachedWorld.java +++ b/src/main/java/baritone/cache/CachedWorld.java @@ -18,6 +18,7 @@ package baritone.cache; import baritone.Baritone; +import baritone.api.cache.ICachedWorld; import baritone.utils.Helper; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -36,7 +37,7 @@ import java.util.concurrent.LinkedBlockingQueue; * @author Brady * @since 8/4/2018 12:02 AM */ -public final class CachedWorld implements Helper { +public final class CachedWorld implements ICachedWorld, Helper { /** * The maximum number of regions in any direction from (0,0) @@ -83,6 +84,7 @@ public final class CachedWorld implements Helper { }); } + @Override public final void queueForPacking(Chunk chunk) { try { toPack.put(chunk); @@ -91,17 +93,17 @@ public final class CachedWorld implements Helper { } } - public final boolean isCached(BlockPos pos) { - int x = pos.getX(); - int z = pos.getZ(); - CachedRegion region = getRegion(x >> 9, z >> 9); + @Override + public final boolean isCached(int blockX, int blockZ) { + CachedRegion region = getRegion(blockX >> 9, blockZ >> 9); if (region == null) { return false; } - return region.isCached(x & 511, z & 511); + return region.isCached(blockX & 511, blockZ & 511); } - public final LinkedList getLocationsOf(String block, int minimum, int maxRegionDistanceSq) { + @Override + public final LinkedList getLocationsOf(String block, int maximum, int maxRegionDistanceSq) { LinkedList res = new LinkedList<>(); int playerRegionX = playerFeet().getX() >> 9; int playerRegionZ = playerFeet().getZ() >> 9; @@ -118,13 +120,12 @@ public final class CachedWorld implements Helper { int regionZ = zoff + playerRegionZ; CachedRegion region = getOrCreateRegion(regionX, regionZ); if (region != null) { - for (BlockPos pos : region.getLocationsOf(block)) { - res.add(pos); - } + // TODO: 100% verify if this or addAll is faster. + region.getLocationsOf(block).forEach(res::add); } } } - if (res.size() >= minimum) { + if (res.size() >= maximum) { return res; } searchRadius++; @@ -137,6 +138,7 @@ public final class CachedWorld implements Helper { region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk); } + @Override public final void save() { if (!Baritone.settings().chunkCaching.get()) { System.out.println("Not saving to disk; chunk caching is disabled."); @@ -156,6 +158,7 @@ public final class CachedWorld implements Helper { return new ArrayList<>(this.cachedRegions.values()); } + @Override public final void reloadAllFromDisk() { long start = System.nanoTime() / 1000000L; allRegions().forEach(region -> { @@ -167,13 +170,7 @@ public final class CachedWorld implements Helper { System.out.println("World load took " + (now - start) + "ms"); } - /** - * Returns the region at the specified region coordinates - * - * @param regionX The region X coordinate - * @param regionZ The region Z coordinate - * @return The region located at the specified coordinates - */ + @Override public final synchronized CachedRegion getRegion(int regionX, int regionZ) { return cachedRegions.get(getRegionID(regionX, regionZ)); } @@ -224,6 +221,7 @@ public final class CachedWorld implements Helper { private class PackerThread implements Runnable { public void run() { while (true) { + // TODO: Add CachedWorld unloading to remove the redundancy of having this LinkedBlockingQueue queue = toPack; if (queue == null) { break; diff --git a/src/main/java/baritone/cache/ChunkPacker.java b/src/main/java/baritone/cache/ChunkPacker.java index 1df1e9c0..4164be3c 100644 --- a/src/main/java/baritone/cache/ChunkPacker.java +++ b/src/main/java/baritone/cache/ChunkPacker.java @@ -89,22 +89,24 @@ public final class ChunkPacker implements Helper { } //long end = System.nanoTime() / 1000000L; //System.out.println("Chunk packing took " + (end - start) + "ms for " + chunk.x + "," + chunk.z); - String[] blockNames = new String[256]; + IBlockState[] blocks = new IBlockState[256]; + for (int z = 0; z < 16; z++) { + // @formatter:off https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html + // @formatter:on for (int x = 0; x < 16; x++) { for (int y = 255; y >= 0; y--) { int index = CachedChunk.getPositionIndex(x, y, z); if (bitSet.get(index) || bitSet.get(index + 1)) { - String name = blockToString(chunk.getBlockState(x, y, z).getBlock()); - blockNames[z << 4 | x] = name; + blocks[z << 4 | x] = chunk.getBlockState(x, y, z); continue https; } } - blockNames[z << 4 | x] = "air"; + blocks[z << 4 | x] = Blocks.AIR.getDefaultState(); } } - return new CachedChunk(chunk.x, chunk.z, bitSet, blockNames, specialBlocks); + return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks); } public static String blockToString(Block block) { diff --git a/src/main/java/baritone/cache/Waypoint.java b/src/main/java/baritone/cache/Waypoint.java index 4fd6c57a..00f4410a 100644 --- a/src/main/java/baritone/cache/Waypoint.java +++ b/src/main/java/baritone/cache/Waypoint.java @@ -17,77 +17,82 @@ package baritone.cache; -import com.google.common.collect.ImmutableList; +import baritone.api.cache.IWaypoint; import net.minecraft.util.math.BlockPos; -import org.apache.commons.lang3.ArrayUtils; import java.util.Date; -import java.util.List; /** - * A single waypoint + * Basic implementation of {@link IWaypoint} * * @author leijurv */ -public class Waypoint { +public class Waypoint implements IWaypoint { - public final String name; - public final Tag tag; + private final String name; + private final Tag tag; private final long creationTimestamp; - public final BlockPos location; + private final BlockPos location; public Waypoint(String name, Tag tag, BlockPos location) { this(name, tag, location, System.currentTimeMillis()); } - Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { // read from disk + /** + * 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 creationTimestamp When the waypoint was created + */ + Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { this.name = name; this.tag = tag; this.location = location; this.creationTimestamp = creationTimestamp; } - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (!(o instanceof Waypoint)) { - return false; - } - Waypoint w = (Waypoint) o; - return name.equals(w.name) && tag == w.tag && location.equals(w.location); - } - @Override public int hashCode() { return name.hashCode() + tag.hashCode() + location.hashCode(); //lol } - public long creationTimestamp() { - return creationTimestamp; + @Override + public String getName() { + return this.name; } + @Override + public Tag getTag() { + return this.tag; + } + + @Override + public long getCreationTimestamp() { + return this.creationTimestamp; + } + + @Override + public BlockPos getLocation() { + return this.location; + } + + @Override public String toString() { return name + " " + location.toString() + " " + new Date(creationTimestamp).toString(); } - public enum Tag { - HOME("home", "base"), - DEATH("death"), - BED("bed", "spawn"), - USER("user"); - - private static final List TAG_LIST = ImmutableList.builder().add(Tag.values()).build(); - - private final String[] names; - - Tag(String... names) { - this.names = names; + @Override + public boolean equals(Object o) { + if (o == null) { + return false; } - - public static Tag fromString(String name) { - return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null); + if (!(o instanceof IWaypoint)) { + return false; } + IWaypoint w = (IWaypoint) o; + return name.equals(w.getName()) && tag == w.getTag() && location.equals(w.getLocation()); } } diff --git a/src/main/java/baritone/cache/Waypoints.java b/src/main/java/baritone/cache/Waypoints.java index be76e34e..2122ddaf 100644 --- a/src/main/java/baritone/cache/Waypoints.java +++ b/src/main/java/baritone/cache/Waypoints.java @@ -17,19 +17,22 @@ package baritone.cache; +import baritone.api.cache.IWaypoint; +import baritone.api.cache.IWaypointCollection; import net.minecraft.util.math.BlockPos; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.stream.Collectors; /** * Waypoints for a world * * @author leijurv */ -public class Waypoints { +public class Waypoints implements IWaypointCollection { /** * Magic value to detect invalid waypoint files @@ -37,7 +40,7 @@ public class Waypoints { private static final long WAYPOINT_MAGIC_VALUE = 121977993584L; // good value private final Path directory; - private final Map> waypoints; + private final Map> waypoints; Waypoints(Path directory) { this.directory = directory; @@ -58,9 +61,9 @@ public class Waypoints { } private synchronized void load(Waypoint.Tag tag) { - waypoints.put(tag, new HashSet<>()); + this.waypoints.put(tag, new HashSet<>()); - Path fileName = directory.resolve(tag.name().toLowerCase() + ".mp4"); + Path fileName = this.directory.resolve(tag.name().toLowerCase() + ".mp4"); if (!Files.exists(fileName)) { return; } @@ -82,44 +85,60 @@ public class Waypoints { int x = in.readInt(); int y = in.readInt(); int z = in.readInt(); - waypoints.get(tag).add(new Waypoint(name, tag, new BlockPos(x, y, z), creationTimestamp)); + this.waypoints.get(tag).add(new Waypoint(name, tag, new BlockPos(x, y, z), creationTimestamp)); } } catch (IOException ignored) {} } private synchronized void save(Waypoint.Tag tag) { - Path fileName = directory.resolve(tag.name().toLowerCase() + ".mp4"); + Path fileName = this.directory.resolve(tag.name().toLowerCase() + ".mp4"); try ( FileOutputStream fileOut = new FileOutputStream(fileName.toFile()); BufferedOutputStream bufOut = new BufferedOutputStream(fileOut); DataOutputStream out = new DataOutputStream(bufOut) ) { out.writeLong(WAYPOINT_MAGIC_VALUE); - out.writeLong(waypoints.get(tag).size()); - for (Waypoint waypoint : waypoints.get(tag)) { - out.writeUTF(waypoint.name); - out.writeLong(waypoint.creationTimestamp()); - out.writeInt(waypoint.location.getX()); - out.writeInt(waypoint.location.getY()); - out.writeInt(waypoint.location.getZ()); + out.writeLong(this.waypoints.get(tag).size()); + for (IWaypoint waypoint : this.waypoints.get(tag)) { + out.writeUTF(waypoint.getName()); + out.writeLong(waypoint.getCreationTimestamp()); + out.writeInt(waypoint.getLocation().getX()); + out.writeInt(waypoint.getLocation().getY()); + out.writeInt(waypoint.getLocation().getZ()); } } catch (IOException ex) { ex.printStackTrace(); } } - public Set getByTag(Waypoint.Tag tag) { - return Collections.unmodifiableSet(waypoints.get(tag)); - } - - public Waypoint getMostRecentByTag(Waypoint.Tag tag) { - // Find a waypoint of the given tag which has the greatest timestamp value, indicating the most recent - return this.waypoints.get(tag).stream().min(Comparator.comparingLong(w -> -w.creationTimestamp())).orElse(null); - } - - public void addWaypoint(Waypoint waypoint) { + @Override + public void addWaypoint(IWaypoint waypoint) { // no need to check for duplicate, because it's a Set not a List - waypoints.get(waypoint.tag).add(waypoint); - save(waypoint.tag); + if (waypoints.get(waypoint.getTag()).add(waypoint)) { + save(waypoint.getTag()); + } + } + + @Override + public void removeWaypoint(IWaypoint waypoint) { + if (waypoints.get(waypoint.getTag()).remove(waypoint)) { + save(waypoint.getTag()); + } + } + + @Override + public IWaypoint getMostRecentByTag(IWaypoint.Tag tag) { + // Find a waypoint of the given tag which has the greatest timestamp value, indicating the most recent + return this.waypoints.get(tag).stream().min(Comparator.comparingLong(w -> -w.getCreationTimestamp())).orElse(null); + } + + @Override + public Set getByTag(IWaypoint.Tag tag) { + return Collections.unmodifiableSet(this.waypoints.get(tag)); + } + + @Override + public Set getAllWaypoints() { + return this.waypoints.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); } } diff --git a/src/main/java/baritone/cache/WorldData.java b/src/main/java/baritone/cache/WorldData.java index 7866e9e8..19461d22 100644 --- a/src/main/java/baritone/cache/WorldData.java +++ b/src/main/java/baritone/cache/WorldData.java @@ -18,6 +18,9 @@ package baritone.cache; import baritone.Baritone; +import baritone.api.cache.ICachedWorld; +import baritone.api.cache.IWaypointCollection; +import baritone.api.cache.IWorldData; import java.nio.file.Path; @@ -26,9 +29,10 @@ import java.nio.file.Path; * * @author leijurv */ -public class WorldData { +public class WorldData implements IWorldData { + public final CachedWorld cache; - public final Waypoints waypoints; + private final Waypoints waypoints; //public final MapData map; public final Path directory; @@ -44,4 +48,14 @@ public class WorldData { cache.save(); }); } + + @Override + public ICachedWorld getCachedWorld() { + return this.cache; + } + + @Override + public IWaypointCollection getWaypoints() { + return this.waypoints; + } } diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index 2cd0b6dc..2aef54c6 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -18,6 +18,7 @@ package baritone.cache; import baritone.Baritone; +import baritone.api.cache.IWorldProvider; import baritone.utils.Helper; import baritone.utils.accessor.IAnvilChunkLoader; import baritone.utils.accessor.IChunkProviderServer; @@ -38,7 +39,7 @@ import java.util.function.Consumer; * @author Brady * @since 8/4/2018 11:06 AM */ -public enum WorldProvider implements Helper { +public enum WorldProvider implements IWorldProvider, Helper { INSTANCE; @@ -46,6 +47,7 @@ public enum WorldProvider implements Helper { private WorldData currentWorld; + @Override public final WorldData getCurrentWorld() { return this.currentWorld; } diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java index 934dd532..61756e33 100644 --- a/src/main/java/baritone/event/GameEventHandler.java +++ b/src/main/java/baritone/event/GameEventHandler.java @@ -109,7 +109,7 @@ public final class GameEventHandler implements IGameEventListener, Helper { if (isPostPopulate || isPreUnload) { WorldProvider.INSTANCE.ifWorldLoaded(world -> { Chunk chunk = mc.world.getChunk(event.getX(), event.getZ()); - world.cache.queueForPacking(chunk); + world.getCachedWorld().queueForPacking(chunk); }); } diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index 0c0d9873..ea56925d 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -18,22 +18,16 @@ package baritone.pathing.calc; import baritone.Baritone; -import baritone.cache.CachedWorld; -import baritone.cache.WorldProvider; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.movement.ActionCosts; import baritone.pathing.calc.openset.BinaryHeapOpenSet; -import baritone.pathing.goals.Goal; -import baritone.pathing.movement.ActionCosts; import baritone.pathing.movement.CalculationContext; -import baritone.pathing.movement.Movement; -import baritone.pathing.movement.MovementHelper; -import baritone.pathing.movement.movements.*; +import baritone.pathing.movement.Moves; import baritone.pathing.path.IPath; import baritone.utils.BlockStateInterface; import baritone.utils.Helper; import baritone.utils.pathing.BetterBlockPos; -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ChunkProviderClient; -import net.minecraft.util.EnumFacing; +import baritone.utils.pathing.MoveResult; import net.minecraft.util.math.BlockPos; import java.util.*; @@ -43,20 +37,18 @@ import java.util.*; * * @author leijurv */ -public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { +public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper { - private final Optional> favoredPositions; + private final Optional> favoredPositions; - private final Random random = new Random(); - - public AStarPathFinder(BlockPos start, Goal goal, Optional> favoredPositions) { + public AStarPathFinder(BlockPos start, Goal goal, Optional> favoredPositions) { super(start, goal); - this.favoredPositions = favoredPositions.map(HashSet::new); // <-- okay this is epic + this.favoredPositions = favoredPositions; } @Override protected Optional calculate0(long timeout) { - startNode = getNodeAtPosition(start); + startNode = getNodeAtPosition(start.x, start.y, start.z); startNode.cost = 0; startNode.combinedCost = startNode.estimatedCostToGoal; BinaryHeapOpenSet openSet = new BinaryHeapOpenSet(); @@ -69,9 +61,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { bestSoFar[i] = startNode; } CalculationContext calcContext = new CalculationContext(); - HashSet favored = favoredPositions.orElse(null); - CachedWorld cachedWorld = Optional.ofNullable(WorldProvider.INSTANCE.getCurrentWorld()).map(w -> w.cache).orElse(null); - ChunkProviderClient chunkProvider = Minecraft.getMinecraft().world.getChunkProvider(); + HashSet favored = favoredPositions.orElse(null); BlockStateInterface.clearCachedChunk(); long startTime = System.nanoTime() / 1000000L; boolean slowPath = Baritone.settings().slowPath.get(); @@ -88,10 +78,10 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get(); - HashMap, Long> timeConsumed = new HashMap<>(); - HashMap, Integer> count = new HashMap<>(); - HashMap, Integer> stateLookup = new HashMap<>(); - HashMap, Long> posCreation = new HashMap<>(); + long[] timeConsumed = new long[Moves.values().length]; + int[] count = new int[Moves.values().length]; + int[] stateLookup = new int[Moves.values().length]; + long[] posCreation = new long[Moves.values().length]; long heapRemove = 0; int heapRemoveCount = 0; long heapAdd = 0; @@ -99,9 +89,6 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { long heapUpdate = 0; int heapUpdateCount = 0; - long construction = 0; - int constructionCount = 0; - long chunk = 0; int chunkCount = 0; @@ -129,36 +116,24 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { heapRemoveCount++; currentNode.isOpen = false; mostRecentConsidered = currentNode; - BetterBlockPos currentNodePos = currentNode.pos; numNodes++; - if (goal.isInGoal(currentNodePos)) { + 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)); } - long constructStart = System.nanoTime(); - goalCheck += constructStart - t; + goalCheck += System.nanoTime() - t; goalCheckCount++; - Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos, in random order - shuffle(possibleMovements); - long constructEnd = System.nanoTime(); - construction += constructEnd - constructStart; - constructionCount++; - for (Movement movementToGetToNeighbor : possibleMovements) { - if (movementToGetToNeighbor == null) { - continue; - } - BetterBlockPos dest = movementToGetToNeighbor.getDest(); + for (Moves moves : Moves.values()) { long s = System.nanoTime(); - int chunkX = currentNodePos.x >> 4; - int chunkZ = currentNodePos.z >> 4; - if (dest.x >> 4 != chunkX || dest.z >> 4 != chunkZ) { + int newX = currentNode.x + moves.xOffset; + int newZ = currentNode.z + moves.zOffset; + if (newX >> 4 != currentNode.x >> 4 || newZ >> 4 != currentNode.z >> 4) { // 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 (chunkProvider.isChunkGeneratedAt(chunkX, chunkZ)) { - // see issue #106 - if (cachedWorld == null || !cachedWorld.isCached(dest)) { + if (!BlockStateInterface.isLoaded(newX, newZ)) { + if (!moves.dynamicXZ) { // only increment the counter if the movement would have gone out of bounds guaranteed numEmptyChunk++; - continue; } + continue; } } long costStart = System.nanoTime(); @@ -167,31 +142,39 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { // TODO cache cost int numLookupsBefore = BlockStateInterface.numBlockStateLookups; long numCreatedBefore = BetterBlockPos.numCreated; - double actionCost = movementToGetToNeighbor.getCost(calcContext); + + MoveResult res = moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z); + long costEnd = System.nanoTime(); - stateLookup.put(movementToGetToNeighbor.getClass(), BlockStateInterface.numBlockStateLookups - numLookupsBefore + stateLookup.getOrDefault(movementToGetToNeighbor.getClass(), 0)); - posCreation.put(movementToGetToNeighbor.getClass(), BetterBlockPos.numCreated - numCreatedBefore + posCreation.getOrDefault(movementToGetToNeighbor.getClass(), 0L)); - timeConsumed.put(movementToGetToNeighbor.getClass(), costEnd - costStart + timeConsumed.getOrDefault(movementToGetToNeighbor.getClass(), 0L)); - count.put(movementToGetToNeighbor.getClass(), 1 + count.getOrDefault(movementToGetToNeighbor.getClass(), 0)); + stateLookup[moves.ordinal()] += BlockStateInterface.numBlockStateLookups - numLookupsBefore; + posCreation[moves.ordinal()] += BetterBlockPos.numCreated - numCreatedBefore; + timeConsumed[moves.ordinal()] += costEnd - costStart; + count[moves.ordinal()]++; + numMovementsConsidered++; + double actionCost = res.cost; if (actionCost >= ActionCosts.COST_INF) { continue; } - if (actionCost <= 0) { - throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost); + // check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation + if (!moves.dynamicXZ && (res.destX != newX || res.destZ != newZ)) { + throw new IllegalStateException(moves + " " + res.destX + " " + newX + " " + res.destZ + " " + newZ); } - if (favoring && favored.contains(dest)) { + if (actionCost <= 0) { + throw new IllegalStateException(moves + " calculated implausible cost " + actionCost); + } + if (favoring && favored.contains(posHash(res.destX, res.destY, res.destZ))) { // see issue #18 actionCost *= favorCoeff; } long st = System.nanoTime(); - PathNode neighbor = getNodeAtPosition(dest); + PathNode neighbor = getNodeAtPosition(res.destX, res.destY, res.destZ); getNode += System.nanoTime() - st; getNodeCount++; double tentativeCost = currentNode.cost + actionCost; if (tentativeCost < neighbor.cost) { if (tentativeCost < 0) { - throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost); + throw new IllegalStateException(moves + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost); } double improvementBy = neighbor.cost - tentativeCost; // there are floating point errors caused by random combinations of traverse and diagonal over a flat area @@ -202,7 +185,6 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { continue; } neighbor.previous = currentNode; - neighbor.previousMovement = movementToGetToNeighbor; neighbor.cost = tentativeCost; neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal; if (neighbor.isOpen) { @@ -235,21 +217,20 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { long numSuccc = BetterBlockPos.numCreated - startVal3; System.out.println("Out of " + numBlockState + " block state lookups, " + numSucc + " were in the same chunk as the previous and could be cached"); System.out.println("Instantiated " + numSuccc + " BetterBlockPos objects"); - System.out.println("Remove " + (heapRemove / heapRemoveCount) + " " + heapRemove / 1000000 + " " + heapRemoveCount); - System.out.println("Add " + (heapAdd / heapAddCount) + " " + heapAdd / 1000000 + " " + heapAddCount); - System.out.println("Update " + (heapUpdate / heapUpdateCount) + " " + heapUpdate / 1000000 + " " + heapUpdateCount); - System.out.println("Construction " + (construction / constructionCount) + " " + construction / 1000000 + " " + constructionCount); - System.out.println("Chunk " + (chunk / chunkCount) + " " + chunk / 1000000 + " " + chunkCount); - System.out.println("GetNode " + (getNode / getNodeCount) + " " + getNode / 1000000 + " " + getNodeCount); - System.out.println("GoalCheck " + (goalCheck / goalCheckCount) + " " + goalCheck / 1000000 + " " + goalCheckCount); - ArrayList> klasses = new ArrayList<>(count.keySet()); - klasses.sort(Comparator.comparingLong(k -> timeConsumed.get(k) / count.get(k))); - for (Class klass : klasses) { - int num = count.get(klass); - long nanoTime = timeConsumed.get(klass); - System.out.println(nanoTime / num + " " + klass + " " + nanoTime / 1000000 + "ms " + num); - System.out.println(stateLookup.get(klass) / num + " " + stateLookup.get(klass)); - System.out.println(posCreation.get(klass) / num + " " + posCreation.get(klass)); + System.out.println("Remove " + (heapRemove / heapRemoveCount) + " " + heapRemove / 1000000 + "ms " + heapRemoveCount); + System.out.println("Add " + (heapAdd / heapAddCount) + " " + heapAdd / 1000000 + "ms " + heapAddCount); + System.out.println("Update " + (heapUpdate / heapUpdateCount) + " " + heapUpdate / 1000000 + "ms " + heapUpdateCount); + System.out.println("Chunk " + (chunk / chunkCount) + " " + chunk / 1000000 + "ms " + chunkCount); + System.out.println("GetNode " + (getNode / getNodeCount) + " " + getNode / 1000000 + "ms " + getNodeCount); + System.out.println("GoalCheck " + (goalCheck / goalCheckCount) + " " + goalCheck / 1000000 + "ms " + goalCheckCount); + ArrayList moves = new ArrayList<>(Arrays.asList(Moves.values())); + moves.sort(Comparator.comparingLong(k -> timeConsumed[k.ordinal()] / count[k.ordinal()])); + for (Moves move : moves) { + int num = count[move.ordinal()]; + long nanoTime = timeConsumed[move.ordinal()]; + System.out.println(nanoTime / num + " " + move + " " + nanoTime / 1000000 + "ms " + num); + System.out.println(stateLookup[move.ordinal()] / num + " " + stateLookup[move.ordinal()]); + System.out.println(posCreation[move.ordinal()] / num + " " + posCreation[move.ordinal()]); } if (cancelRequested) { return Optional.empty(); @@ -282,56 +263,4 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { logDebug("No path found =("); return Optional.empty(); } - - - public static Movement[] getConnectedPositions(BetterBlockPos pos, CalculationContext calcContext) { - int x = pos.x; - int y = pos.y; - int z = pos.z; - BetterBlockPos east = new BetterBlockPos(x + 1, y, z); - BetterBlockPos west = new BetterBlockPos(x - 1, y, z); - BetterBlockPos south = new BetterBlockPos(x, y, z + 1); - BetterBlockPos north = new BetterBlockPos(x, y, z - 1); - return new Movement[]{ - new MovementDownward(pos, new BetterBlockPos(x, y - 1, z)), - - new MovementPillar(pos, new BetterBlockPos(x, y + 1, z)), - - new MovementTraverse(pos, east), - new MovementTraverse(pos, west), - new MovementTraverse(pos, north), - new MovementTraverse(pos, south), - - new MovementAscend(pos, new BetterBlockPos(x + 1, y + 1, z)), - new MovementAscend(pos, new BetterBlockPos(x - 1, y + 1, z)), - new MovementAscend(pos, new BetterBlockPos(x, y + 1, z + 1)), - new MovementAscend(pos, new BetterBlockPos(x, y + 1, z - 1)), - - MovementHelper.generateMovementFallOrDescend(pos, east, calcContext), - MovementHelper.generateMovementFallOrDescend(pos, west, calcContext), - MovementHelper.generateMovementFallOrDescend(pos, north, calcContext), - MovementHelper.generateMovementFallOrDescend(pos, south, calcContext), - - new MovementDiagonal(pos, EnumFacing.NORTH, EnumFacing.EAST), - new MovementDiagonal(pos, EnumFacing.NORTH, EnumFacing.WEST), - new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.EAST), - - new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.WEST), - - MovementParkour.generate(pos, EnumFacing.EAST, calcContext), - MovementParkour.generate(pos, EnumFacing.WEST, calcContext), - MovementParkour.generate(pos, EnumFacing.NORTH, calcContext), - MovementParkour.generate(pos, EnumFacing.SOUTH, calcContext), - }; - } - - private void shuffle(T[] list) { - int len = list.length; - for (int i = 0; i < len; i++) { - int j = random.nextInt(len); - T t = list[j]; - list[j] = list[i]; - list[i] = t; - } - } } diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index 012c257c..21f6d848 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -17,8 +17,7 @@ package baritone.pathing.calc; -import baritone.behavior.PathingBehavior; -import baritone.pathing.goals.Goal; +import baritone.api.pathing.goals.Goal; import baritone.pathing.path.IPath; import baritone.utils.pathing.BetterBlockPos; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -115,9 +114,9 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { * @return The distance, squared */ protected double getDistFromStartSq(PathNode n) { - int xDiff = n.pos.x - start.x; - int yDiff = n.pos.y - start.y; - int zDiff = n.pos.z - start.z; + int xDiff = n.x - start.x; + int yDiff = n.y - start.y; + int zDiff = n.z - start.z; return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff; } @@ -126,28 +125,62 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { * for the node mapped to the specified pos. If no node is found, * a new node is created. * - * @param pos The pos to lookup * @return The associated node * @see Issue #107 */ - protected PathNode getNodeAtPosition(BetterBlockPos pos) { - long hashCode = pos.hashCode; + protected PathNode getNodeAtPosition(int x, int y, int z) { + long hashCode = posHash(x, y, z); PathNode node = map.get(hashCode); if (node == null) { - node = new PathNode(pos, goal); + node = new PathNode(x, y, z, goal); map.put(hashCode, node); } return node; } + public static long posHash(int x, int y, int z) { + /* + * This is the hashcode implementation of Vec3i, the superclass of BlockPos + * + * public int hashCode() { + * return (this.getY() + this.getZ() * 31) * 31 + this.getX(); + * } + * + * That is terrible and has tons of collisions and makes the HashMap terribly inefficient. + * + * That's why we grab out the X, Y, Z and calculate our own hashcode + */ + long hash = 3241; + hash = 3457689L * hash + x; + hash = 8734625L * hash + y; + hash = 2873465L * hash + z; + return hash; + } + public static void forceCancel() { - PathingBehavior.INSTANCE.cancel(); currentlyRunning = null; } + public PathNode mostRecentNodeConsidered() { + return mostRecentConsidered; + } + + public PathNode bestNodeSoFar() { + return bestSoFar[0]; + } + + public PathNode startNode() { + return startNode; + } + @Override public Optional pathToMostRecentNodeConsidered() { - return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal)); + try { + return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal)); + } catch (IllegalStateException ex) { + System.out.println("Unable to construct path to render"); + return Optional.empty(); + } } protected int mapSize() { @@ -164,7 +197,12 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { continue; } if (getDistFromStartSq(bestSoFar[i]) > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared - return Optional.of(new Path(startNode, bestSoFar[i], 0, goal)); + try { + return Optional.of(new Path(startNode, bestSoFar[i], 0, goal)); + } catch (IllegalStateException ex) { + System.out.println("Unable to construct path to render"); + return Optional.empty(); + } } } // instead of returning bestSoFar[0], be less misleading diff --git a/src/main/java/baritone/pathing/calc/IPathFinder.java b/src/main/java/baritone/pathing/calc/IPathFinder.java index 3723865d..6ed2b3a7 100644 --- a/src/main/java/baritone/pathing/calc/IPathFinder.java +++ b/src/main/java/baritone/pathing/calc/IPathFinder.java @@ -17,7 +17,7 @@ package baritone.pathing.calc; -import baritone.pathing.goals.Goal; +import baritone.api.pathing.goals.Goal; import baritone.pathing.path.IPath; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index e94f2fb3..7f8cf085 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -17,8 +17,9 @@ package baritone.pathing.calc; -import baritone.pathing.goals.Goal; +import baritone.api.pathing.goals.Goal; import baritone.pathing.movement.Movement; +import baritone.pathing.movement.Moves; import baritone.pathing.path.IPath; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.util.math.BlockPos; @@ -60,8 +61,8 @@ class Path implements IPath { private volatile boolean verified; Path(PathNode start, PathNode end, int numNodes, Goal goal) { - this.start = start.pos; - this.end = end.pos; + 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<>(); @@ -88,11 +89,11 @@ class Path implements IPath { LinkedList tempPath = new LinkedList<>(); // Repeatedly inserting to the beginning of an arraylist is O(n^2) LinkedList tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end while (!current.equals(start)) { - tempPath.addFirst(current.pos); - tempMovements.addFirst(current.previousMovement); + tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z)); + tempMovements.addFirst(runBackwards(current.previous, current)); current = current.previous; } - tempPath.addFirst(start.pos); + 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. @@ -100,6 +101,19 @@ class Path implements IPath { movements.addAll(tempMovements); } + private static Movement runBackwards(PathNode src0, PathNode dest0) { // TODO this is horrifying + BetterBlockPos src = new BetterBlockPos(src0.x, src0.y, src0.z); + BetterBlockPos dest = new BetterBlockPos(dest0.x, dest0.y, dest0.z); + for (Moves moves : Moves.values()) { + Movement move = moves.apply0(src); + if (move.getDest().equals(dest)) { + return move; + } + } + // leave this as IllegalStateException; it's caught in AbstractNodeCostSearch + throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src)); + } + /** * Performs a series of checks to ensure that the assembly of the path went as expected. */ diff --git a/src/main/java/baritone/pathing/calc/PathNode.java b/src/main/java/baritone/pathing/calc/PathNode.java index 8f9895d8..8e42d564 100644 --- a/src/main/java/baritone/pathing/calc/PathNode.java +++ b/src/main/java/baritone/pathing/calc/PathNode.java @@ -17,10 +17,8 @@ package baritone.pathing.calc; -import baritone.pathing.goals.Goal; -import baritone.pathing.movement.ActionCosts; -import baritone.pathing.movement.Movement; -import baritone.utils.pathing.BetterBlockPos; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.movement.ActionCosts; /** * A node in the path, containing the cost and steps to get to it. @@ -32,12 +30,9 @@ public final class PathNode { /** * The position of this node */ - final BetterBlockPos pos; - - /** - * The goal it's going towards - */ - final Goal goal; + final int x; + final int y; + final int z; /** * Cached, should always be equal to goal.heuristic(pos) @@ -62,12 +57,6 @@ public final class PathNode { */ PathNode previous; - /** - * In the graph search, what previous movement (edge) was taken to get to here - * Mutable and changed by PathFinder - */ - Movement previousMovement; - /** * Is this a member of the open set in A*? (only used during pathfinding) * Instead of doing a costly member check in the open set, cache membership in each node individually too. @@ -79,14 +68,14 @@ public final class PathNode { */ public int heapPosition; - public PathNode(BetterBlockPos pos, Goal goal) { - this.pos = pos; + public PathNode(int x, int y, int z, Goal goal) { this.previous = null; this.cost = ActionCosts.COST_INF; - this.goal = goal; - this.estimatedCostToGoal = goal.heuristic(pos); - this.previousMovement = null; + this.estimatedCostToGoal = goal.heuristic(x, y, z); this.isOpen = false; + this.x = x; + this.y = y; + this.z = z; } /** @@ -96,7 +85,7 @@ public final class PathNode { */ @Override public int hashCode() { - return pos.hashCode() * 7 + 3; + return (int) AbstractNodeCostSearch.posHash(x, y, z); } @Override @@ -108,8 +97,9 @@ public final class PathNode { // return false; //} - //final PathNode other = (PathNode) obj; + final PathNode other = (PathNode) obj; //return Objects.equals(this.pos, other.pos) && Objects.equals(this.goal, other.goal); - return this.pos.equals(((PathNode) obj).pos); + + return x == other.x && y == other.y && z == other.z; } } diff --git a/src/main/java/baritone/pathing/movement/ActionCosts.java b/src/main/java/baritone/pathing/movement/ActionCosts.java deleted file mode 100644 index cbfcd810..00000000 --- a/src/main/java/baritone/pathing/movement/ActionCosts.java +++ /dev/null @@ -1,47 +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.pathing.movement; - -public interface ActionCosts extends ActionCostsButOnlyTheOnesThatMakeMickeyDieInside { - - /** - * These costs are measured roughly in ticks btw - */ - double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633 - double WALK_ONE_IN_WATER_COST = 20 / 2.2; - double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_BLOCK_COST * 2; // 0.4 in BlockSoulSand but effectively about half - double SPRINT_ONE_OVER_SOUL_SAND_COST = WALK_ONE_OVER_SOUL_SAND_COST * 0.75; - double LADDER_UP_ONE_COST = 20 / 2.35; - double LADDER_DOWN_ONE_COST = 20 / 3.0; - double SNEAK_ONE_BLOCK_COST = 20 / 1.3; - double SPRINT_ONE_BLOCK_COST = 20 / 5.612; // 3.564 - /** - * To walk off an edge you need to walk 0.5 to the edge then 0.3 to start falling off - */ - double WALK_OFF_BLOCK_COST = WALK_ONE_BLOCK_COST * 0.8; - /** - * To walk the rest of the way to be centered on the new block - */ - double CENTER_AFTER_FALL_COST = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST; - - /** - * don't make this Double.MAX_VALUE because it's added to other things, maybe other COST_INFs, - * and that would make it overflow to negative - */ - double COST_INF = 1000000; -} diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index 4fbc17f0..21341fa4 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -18,18 +18,19 @@ package baritone.pathing.movement; import baritone.Baritone; +import baritone.api.utils.Rotation; import baritone.behavior.LookBehavior; import baritone.behavior.LookBehaviorUtils; import baritone.pathing.movement.MovementState.MovementStatus; import baritone.utils.*; import baritone.utils.pathing.BetterBlockPos; +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.Arrays; import java.util.List; import java.util.Optional; @@ -158,8 +159,8 @@ public abstract class Movement implements Helper, MovementHelper { return true; } boolean somethingInTheWay = false; - for (BlockPos blockPos : positionsToBreak) { - if (!MovementHelper.canWalkThrough(blockPos)) { + 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 = LookBehaviorUtils.reachable(blockPos); if (reachable.isPresent()) { @@ -218,60 +219,6 @@ public abstract class Movement implements Helper, MovementHelper { currentState = new MovementState().setStatus(MovementStatus.PREPPING); } - public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) { - if (positionsToBreak.length == 0) { - return 0; - } - if (positionsToBreak.length == 1) { - return MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[0], true); - } - int firstColumnX = positionsToBreak[0].getX(); - int firstColumnZ = positionsToBreak[0].getZ(); - int firstColumnMaxY = positionsToBreak[0].getY(); - int firstColumnMaximalIndex = 0; - boolean hasSecondColumn = false; - int secondColumnX = -1; - int secondColumnZ = -1; - int secondColumnMaxY = -1; - int secondColumnMaximalIndex = -1; - for (int i = 0; i < positionsToBreak.length; i++) { - BlockPos pos = positionsToBreak[i]; - if (pos.getX() == firstColumnX && pos.getZ() == firstColumnZ) { - if (pos.getY() > firstColumnMaxY) { - firstColumnMaxY = pos.getY(); - firstColumnMaximalIndex = i; - } - } else { - if (!hasSecondColumn || (pos.getX() == secondColumnX && pos.getZ() == secondColumnZ)) { - if (hasSecondColumn) { - if (pos.getY() > secondColumnMaxY) { - secondColumnMaxY = pos.getY(); - secondColumnMaximalIndex = i; - } - } else { - hasSecondColumn = true; - secondColumnX = pos.getX(); - secondColumnZ = pos.getZ(); - secondColumnMaxY = pos.getY(); - secondColumnMaximalIndex = i; - } - } else { - throw new IllegalStateException("I literally have no idea " + Arrays.asList(positionsToBreak)); - } - } - } - - double sum = 0; - for (int i = 0; i < positionsToBreak.length; i++) { - sum += MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[i], firstColumnMaximalIndex == i || secondColumnMaximalIndex == i); - if (sum >= COST_INF) { - break; - } - } - return sum; - } - - /** * Calculate latest movement state. * Gets called once a tick. @@ -309,7 +256,7 @@ public abstract class Movement implements Helper, MovementHelper { return toBreakCached; } List result = new ArrayList<>(); - for (BlockPos positionToBreak : positionsToBreak) { + for (BetterBlockPos positionToBreak : positionsToBreak) { if (!MovementHelper.canWalkThrough(positionToBreak)) { result.add(positionToBreak); } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 421f3150..6613c671 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -18,10 +18,10 @@ package baritone.pathing.movement; import baritone.Baritone; +import baritone.api.pathing.movement.ActionCosts; +import baritone.api.utils.Rotation; import baritone.behavior.LookBehaviorUtils; import baritone.pathing.movement.MovementState.MovementTarget; -import baritone.pathing.movement.movements.MovementDescend; -import baritone.pathing.movement.movements.MovementFall; import baritone.utils.*; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.*; @@ -47,11 +47,12 @@ import java.util.Optional; */ public interface MovementHelper extends ActionCosts, Helper { - static boolean avoidBreaking(BlockPos pos, IBlockState state) { + static boolean avoidBreaking(BetterBlockPos pos, IBlockState state) { + return avoidBreaking(pos.x, pos.y, pos.z, state); + } + + static boolean avoidBreaking(int x, int y, int z, IBlockState state) { Block b = state.getBlock(); - int x = pos.getX(); - int y = pos.getY(); - int z = pos.getZ(); 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 @@ -68,13 +69,21 @@ public interface MovementHelper extends ActionCosts, Helper { * @param pos * @return */ - static boolean canWalkThrough(BlockPos pos) { - return canWalkThrough(pos, BlockStateInterface.get(pos)); + static boolean canWalkThrough(BetterBlockPos pos) { + return canWalkThrough(pos.x, pos.y, pos.z, BlockStateInterface.get(pos)); } - static boolean canWalkThrough(BlockPos pos, IBlockState state) { + static boolean canWalkThrough(BetterBlockPos pos, IBlockState state) { + return canWalkThrough(pos.x, pos.y, pos.z, state); + } + + static boolean canWalkThrough(int x, int y, int z) { + return canWalkThrough(x, y, z, BlockStateInterface.get(x, y, z)); + } + + static boolean canWalkThrough(int x, int y, int z, IBlockState state) { Block block = state.getBlock(); - if (block == Blocks.AIR) { + if (block == Blocks.AIR) { // early return for most common case return true; } if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL) { @@ -86,14 +95,23 @@ public interface MovementHelper extends ActionCosts, Helper { // be opened by just interacting. return block != Blocks.IRON_DOOR; } - if (block instanceof BlockSnow || block instanceof BlockTrapDoor) { - // we've already checked doors - // so the only remaining dynamic isPassables are snow, fence gate, and trapdoor + boolean snow = block instanceof BlockSnow; + boolean trapdoor = block instanceof BlockTrapDoor; + if (snow || trapdoor) { + // we've already checked doors and fence gates + // so the only remaining dynamic isPassables are snow and trapdoor // if they're cached as a top block, we don't know their metadata // default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible) - if (mc.world.getChunk(pos) instanceof EmptyChunk) { + if (mc.world.getChunk(x >> 4, z >> 4) instanceof EmptyChunk) { return true; } + if (snow) { + return state.getValue(BlockSnow.LAYERS) < 5; // see BlockSnow.isPassable + } + if (trapdoor) { + return !state.getValue(BlockTrapDoor.OPEN); // see BlockTrapDoor.isPassable + } + throw new IllegalStateException(); } if (BlockStateInterface.isFlowing(state)) { return false; // Don't walk through flowing liquids @@ -102,13 +120,16 @@ public interface MovementHelper extends ActionCosts, Helper { if (Baritone.settings().assumeWalkOnWater.get()) { return false; } - IBlockState up = BlockStateInterface.get(pos.up()); + IBlockState up = BlockStateInterface.get(x, y + 1, z); if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) { return false; } return block == Blocks.WATER || block == Blocks.FLOWING_WATER; } - return block.isPassable(mc.world, pos); // only blocks that can get here and actually that use world and pos for this call are snow and trapdoor + // every block that overrides isPassable with anything more complicated than a "return true;" or "return false;" + // has already been accounted for above + // therefore it's safe to not construct a blockpos from our x, y, z ints and instead just pass null + return block.isPassable(null, null); } /** @@ -118,12 +139,16 @@ public interface MovementHelper extends ActionCosts, Helper { * @return */ static boolean fullyPassable(BlockPos pos) { - return fullyPassable(pos, BlockStateInterface.get(pos)); + return fullyPassable(BlockStateInterface.get(pos)); } - static boolean fullyPassable(BlockPos pos, IBlockState state) { + static boolean fullyPassable(int x, int y, int z) { + return fullyPassable(BlockStateInterface.get(x, y, z)); + } + + static boolean fullyPassable(IBlockState state) { Block block = state.getBlock(); - if (block == Blocks.AIR) { + if (block == Blocks.AIR) { // early return for most common case return true; } // exceptions - blocks that are isPassable true, but we can't actually jump through @@ -140,10 +165,15 @@ public interface MovementHelper extends ActionCosts, Helper { || block instanceof BlockEndPortal) { return false; } - return block.isPassable(mc.world, pos); + // door, fence gate, liquid, trapdoor have been accounted for, nothing else uses the world or pos parameters + return block.isPassable(null, null); } static boolean isReplacable(BlockPos pos, IBlockState state) { + return isReplacable(pos.getX(), pos.getY(), pos.getZ(), state); + } + + static boolean isReplacable(int x, int y, int z, IBlockState state) { // for MovementTraverse and MovementAscend // block double plant defaults to true when the block doesn't match, so don't need to check that case // all other overrides just return true or false @@ -154,13 +184,19 @@ public interface MovementHelper extends ActionCosts, Helper { * return ((Integer)worldIn.getBlockState(pos).getValue(LAYERS)).intValue() == 1; * } */ - if (state.getBlock() instanceof BlockSnow) { + Block block = state.getBlock(); + if (block instanceof BlockSnow) { // as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible) - if (mc.world.getChunk(pos) instanceof EmptyChunk) { + if (mc.world.getChunk(x >> 4, z >> 4) instanceof EmptyChunk) { return true; } + return state.getValue(BlockSnow.LAYERS) == 1; } - return state.getBlock().isReplaceable(mc.world, pos); + if (block instanceof BlockDoublePlant) { + BlockDoublePlant.EnumPlantType kek = state.getValue(BlockDoublePlant.VARIANT); + return kek == BlockDoublePlant.EnumPlantType.FERN || kek == BlockDoublePlant.EnumPlantType.GRASS; + } + return state.getBlock().isReplaceable(null, null); } static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) { @@ -226,9 +262,11 @@ public interface MovementHelper extends ActionCosts, Helper { * * @return */ - static boolean canWalkOn(BetterBlockPos pos, IBlockState state) { + static boolean canWalkOn(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) + // plus magma, which is a normal cube but it hurts you return false; } if (state.isBlockNormalCube()) { @@ -249,7 +287,7 @@ public interface MovementHelper extends ActionCosts, Helper { if (BlockStateInterface.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(pos.x, pos.y + 1, pos.z).getBlock(); + Block up = BlockStateInterface.get(x, y + 1, z).getBlock(); if (up == Blocks.WATERLILY) { return true; } @@ -279,42 +317,70 @@ public interface MovementHelper extends ActionCosts, Helper { return false; } + static boolean canWalkOn(BetterBlockPos pos, IBlockState state) { + return canWalkOn(pos.x, pos.y, pos.z, state); + } + static boolean canWalkOn(BetterBlockPos pos) { - return canWalkOn(pos, BlockStateInterface.get(pos)); + return canWalkOn(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 canPlaceAgainst(int x, int y, int z) { + return canPlaceAgainst(BlockStateInterface.get(x, y, z)); } static boolean canPlaceAgainst(BlockPos pos) { - IBlockState state = BlockStateInterface.get(pos); + return canPlaceAgainst(BlockStateInterface.get(pos)); + } + + static boolean canPlaceAgainst(IBlockState state) { // TODO isBlockNormalCube isn't the best check for whether or not we can place a block against it. e.g. glass isn't normalCube but we can place against it return state.isBlockNormalCube(); } - static double getMiningDurationTicks(CalculationContext context, BlockPos position, boolean includeFalling) { + static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, + boolean includeFalling) { IBlockState state = BlockStateInterface.get(position); - return getMiningDurationTicks(context, position, state, includeFalling); + return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling); } - static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state, boolean includeFalling) { + static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, IBlockState state, + boolean includeFalling) { + return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling); + } + + 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); + } + + static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, + boolean includeFalling) { Block block = state.getBlock(); - if (!canWalkThrough(position, state)) { + if (!canWalkThrough(x, y, z, state)) { if (!context.allowBreak()) { return COST_INF; } - if (avoidBreaking(position, state)) { + if (avoidBreaking(x, y, z, state)) { + return COST_INF; + } + if (block instanceof BlockLiquid) { return COST_INF; } double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table double strVsBlock = context.getToolSet().getStrVsBlock(state); - if (strVsBlock < 0) { + if (strVsBlock <= 0) { return COST_INF; } double result = m / strVsBlock; if (includeFalling) { - BlockPos up = position.up(); - IBlockState above = BlockStateInterface.get(up); + IBlockState above = BlockStateInterface.get(x, y + 1, z); if (above.getBlock() instanceof BlockFalling) { - result += getMiningDurationTicks(context, up, above, true); + result += getMiningDurationTicks(context, x, y + 1, z, above, true); } } return result; @@ -400,57 +466,8 @@ public interface MovementHelper extends ActionCosts, Helper { state.setTarget(new MovementTarget( new Rotation(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), Utils.getBlockPosCenter(pos), - new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)).getFirst(), mc.player.rotationPitch), + new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)).getYaw(), mc.player.rotationPitch), false )).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); } - - static Movement generateMovementFallOrDescend(BetterBlockPos pos, BetterBlockPos dest, CalculationContext calcContext) { - // A - //SA - // A - // B - // C - // D - //if S is where you start, B needs to be air for a movementfall - //A is plausibly breakable by either descend or fall - //C, D, etc determine the length of the fall - - if (!canWalkThrough(dest.down(2))) { - //if B in the diagram aren't air - //have to do a descend, because fall is impossible - - //this doesn't guarantee descend is possible, it just guarantees fall is impossible - return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1 - // we can't cost shortcut descend because !canWalkThrough doesn't mean canWalkOn - } - - // we're clear for a fall 2 - // let's see how far we can fall - for (int fallHeight = 3; true; fallHeight++) { - BetterBlockPos onto = dest.down(fallHeight); - if (onto.getY() < 0) { - // when pathing in the end, where you could plausibly fall into the void - // this check prevents it from getting the block at y=-1 and crashing - break; - } - IBlockState ontoBlock = BlockStateInterface.get(onto); - if (ontoBlock.getBlock() == Blocks.WATER) { - return new MovementFall(pos, onto); - } - if (canWalkThrough(onto, ontoBlock)) { - continue; - } - if (!canWalkOn(onto, ontoBlock)) { - break; - } - if ((calcContext.hasWaterBucket() && fallHeight <= calcContext.maxFallHeightBucket() + 1) || fallHeight <= calcContext.maxFallHeightNoWater() + 1) { - // fallHeight = 4 means onto.up() is 3 blocks down, which is the max - return new MovementFall(pos, onto.up()); - } else { - return null; - } - } - return null; - } } diff --git a/src/main/java/baritone/pathing/movement/MovementState.java b/src/main/java/baritone/pathing/movement/MovementState.java index 0017c438..6d0262e6 100644 --- a/src/main/java/baritone/pathing/movement/MovementState.java +++ b/src/main/java/baritone/pathing/movement/MovementState.java @@ -17,8 +17,8 @@ package baritone.pathing.movement; +import baritone.api.utils.Rotation; import baritone.utils.InputOverrideHandler.Input; -import baritone.utils.Rotation; import net.minecraft.util.math.Vec3d; import java.util.HashMap; diff --git a/src/main/java/baritone/pathing/movement/Moves.java b/src/main/java/baritone/pathing/movement/Moves.java new file mode 100644 index 00000000..6f49dfbd --- /dev/null +++ b/src/main/java/baritone/pathing/movement/Moves.java @@ -0,0 +1,333 @@ +/* + * 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.movement; + +import baritone.pathing.movement.movements.*; +import baritone.utils.pathing.BetterBlockPos; +import baritone.utils.pathing.MoveResult; +import net.minecraft.util.EnumFacing; + +/** + * An enum of all possible movements attached to all possible directions they could be taken in + * + * @author leijurv + */ +public enum Moves { + DOWNWARD(0, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementDownward(src, src.down()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y - 1, z, MovementDownward.cost(context, x, y, z)); + } + }, + + PILLAR(0, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementPillar(src, src.up()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y + 1, z, MovementPillar.cost(context, x, y, z)); + } + }, + + TRAVERSE_NORTH(0, -1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementTraverse(src, src.north()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y, z - 1, MovementTraverse.cost(context, x, y, z, x, z - 1)); + } + }, + + TRAVERSE_SOUTH(0, +1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementTraverse(src, src.south()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y, z + 1, MovementTraverse.cost(context, x, y, z, x, z + 1)); + } + }, + + TRAVERSE_EAST(+1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementTraverse(src, src.east()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x + 1, y, z, MovementTraverse.cost(context, x, y, z, x + 1, z)); + } + }, + + TRAVERSE_WEST(-1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementTraverse(src, src.west()); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x - 1, y, z, MovementTraverse.cost(context, x, y, z, x - 1, z)); + } + }, + + ASCEND_NORTH(0, -1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z - 1)); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y + 1, z - 1, MovementAscend.cost(context, x, y, z, x, z - 1)); + } + }, + + ASCEND_SOUTH(0, +1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z + 1)); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x, y + 1, z + 1, MovementAscend.cost(context, x, y, z, x, z + 1)); + } + }, + + ASCEND_EAST(+1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementAscend(src, new BetterBlockPos(src.x + 1, src.y + 1, src.z)); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x + 1, y + 1, z, MovementAscend.cost(context, x, y, z, x + 1, z)); + } + }, + + ASCEND_WEST(-1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementAscend(src, new BetterBlockPos(src.x - 1, src.y + 1, src.z)); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x - 1, y + 1, z, MovementAscend.cost(context, x, y, z, x - 1, z)); + } + }, + + DESCEND_EAST(+1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z); + if (res.destY == src.y - 1) { + return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } else { + return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementDescend.cost(context, x, y, z, x + 1, z); + } + }, + + DESCEND_WEST(-1, 0) { + @Override + public Movement apply0(BetterBlockPos src) { + MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z); + if (res.destY == src.y - 1) { + return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } else { + return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementDescend.cost(context, x, y, z, x - 1, z); + } + }, + + DESCEND_NORTH(0, -1) { + @Override + public Movement apply0(BetterBlockPos src) { + MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z); + if (res.destY == src.y - 1) { + return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } else { + return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementDescend.cost(context, x, y, z, x, z - 1); + } + }, + + DESCEND_SOUTH(0, +1) { + @Override + public Movement apply0(BetterBlockPos src) { + MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z); + if (res.destY == src.y - 1) { + return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } else { + return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ)); + } + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementDescend.cost(context, x, y, z, x, z + 1); + } + }, + + DIAGONAL_NORTHEAST(+1, -1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.EAST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x + 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x + 1, z - 1)); + } + }, + + DIAGONAL_NORTHWEST(-1, -1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.WEST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x - 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x - 1, z - 1)); + } + }, + + DIAGONAL_SOUTHEAST(+1, +1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.EAST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x + 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x + 1, z + 1)); + } + }, + + DIAGONAL_SOUTHWEST(-1, +1) { + @Override + public Movement apply0(BetterBlockPos src) { + return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.WEST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return new MoveResult(x - 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x - 1, z + 1)); + } + }, + + PARKOUR_NORTH(0, -4, true) { + @Override + public Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.NORTH); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementParkour.cost(context, x, y, z, EnumFacing.NORTH); + } + }, + + PARKOUR_SOUTH(0, +4, true) { + @Override + public Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.SOUTH); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementParkour.cost(context, x, y, z, EnumFacing.SOUTH); + } + }, + + PARKOUR_EAST(+4, 0, true) { + @Override + public Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.EAST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementParkour.cost(context, x, y, z, EnumFacing.EAST); + } + }, + + PARKOUR_WEST(-4, 0, true) { + @Override + public Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.WEST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + return MovementParkour.cost(context, x, y, z, EnumFacing.WEST); + } + }; + + public final boolean dynamicXZ; + + public final int xOffset; + public final int zOffset; + + Moves(int x, int z, boolean dynamicXZ) { + this.xOffset = x; + this.zOffset = z; + this.dynamicXZ = dynamicXZ; + } + + Moves(int x, int z) { + this(x, z, false); + } + + public abstract Movement apply0(BetterBlockPos src); + + public abstract MoveResult apply(CalculationContext context, int x, int y, int z); +} diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java index 745b8a89..6d313c48 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java @@ -28,7 +28,6 @@ import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.Utils; import baritone.utils.pathing.BetterBlockPos; -import net.minecraft.block.Block; import net.minecraft.block.BlockFalling; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; @@ -55,46 +54,54 @@ public class MovementAscend extends Movement { @Override protected double calculateCost(CalculationContext context) { - IBlockState srcDown = BlockStateInterface.get(src.down()); + return cost(context, src.x, src.y, src.z, dest.x, dest.z); + } + + public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { + IBlockState srcDown = BlockStateInterface.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(positionToPlace); + IBlockState toPlace = BlockStateInterface.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 } - if (!MovementHelper.canWalkOn(positionToPlace, toPlace)) { + boolean hasToPlace = false; + if (!MovementHelper.canWalkOn(destX, y, z, toPlace)) { if (!context.hasThrowaway()) { return COST_INF; } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) { + if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.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 // useful for when you are starting a staircase without anything to place against // Counterpoint to the above TODO ^ you should move then pillar instead of ascend for (int i = 0; i < 4; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS[i]); - if (against1.equals(src)) { + int againstX = destX + HORIZONTALS[i].getXOffset(); + int againstZ = destZ + HORIZONTALS[i].getZOffset(); + if (againstX == x && againstZ == z) { continue; } - if (MovementHelper.canPlaceAgainst(against1)) { - return JUMP_ONE_BLOCK_COST + WALK_ONE_BLOCK_COST + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context); + if (MovementHelper.canPlaceAgainst(againstX, y, againstZ)) { + hasToPlace = true; + break; } } - return COST_INF; + if (!hasToPlace) { // didn't find a valid place =( + return COST_INF; + } } - if (BlockStateInterface.get(src.up(3)).getBlock() instanceof BlockFalling) {//it would fall on us and possibly suffocate us + IBlockState srcUp2 = null; + if (BlockStateInterface.get(x, y + 3, 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 - Block srcUp = BlockStateInterface.get(src.up(1)).getBlock(); - Block srcUp2 = BlockStateInterface.get(src.up(2)).getBlock(); - if (!(srcUp instanceof BlockFalling) || !(srcUp2 instanceof BlockFalling)) { + if (!(BlockStateInterface.getBlock(x, y + 1, z) instanceof BlockFalling) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling)) { // if both of those are BlockFalling, that means that by standing on src // (the presupposition of this Movement) // we have necessarily already cleared the entire BlockFalling stack @@ -109,15 +116,41 @@ public class MovementAscend extends Movement { // it's possible srcUp is AIR from the start, and srcUp2 is falling // and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us } - double walk = WALK_ONE_BLOCK_COST; - if (jumpingToBottomSlab && !jumpingFromBottomSlab) { - return walk + getTotalHardnessOfBlocksToBreak(context); // we don't hit space we just walk into the slab + double walk; + if (jumpingToBottomSlab) { + if (jumpingFromBottomSlab) { + walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); // we hit space immediately on entering this action + } else { + walk = WALK_ONE_BLOCK_COST; // we don't hit space we just walk into the slab + } + } else { + if (toPlace.getBlock() == Blocks.SOUL_SAND) { + walk = WALK_ONE_OVER_SOUL_SAND_COST; + } else { + walk = WALK_ONE_BLOCK_COST; + } } - if (!jumpingToBottomSlab && toPlace.getBlock().equals(Blocks.SOUL_SAND)) { - walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST; + + // cracks knuckles + + double totalCost = 0; + totalCost += walk; + if (hasToPlace) { + totalCost += context.placeBlockCost(); } - // we hit space immediately on entering this action - return Math.max(JUMP_ONE_BLOCK_COST, walk) + getTotalHardnessOfBlocksToBreak(context); + if (srcUp2 == null) { + srcUp2 = BlockStateInterface.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) { + return COST_INF; + } + totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, false); + if (totalCost >= COST_INF) { + return COST_INF; + } + totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 2, destZ, true); + return totalCost; } @Override @@ -202,9 +235,9 @@ public class MovementAscend extends Movement { } private boolean headBonkClear() { - BlockPos startUp = src.up(2); + BetterBlockPos startUp = src.up(2); for (int i = 0; i < 4; i++) { - BlockPos check = startUp.offset(EnumFacing.byHorizontalIndex(i)); + BetterBlockPos check = startUp.offset(EnumFacing.byHorizontalIndex(i)); if (!MovementHelper.canWalkThrough(check)) { // We might bonk our head return false; diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java index 85f7f110..79d5a305 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java @@ -17,6 +17,7 @@ package baritone.pathing.movement.movements; +import baritone.Baritone; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; @@ -25,10 +26,15 @@ import baritone.pathing.movement.MovementState.MovementStatus; import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.pathing.BetterBlockPos; +import baritone.utils.pathing.MoveResult; import net.minecraft.block.Block; +import net.minecraft.block.BlockFalling; +import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.util.math.BlockPos; +import static baritone.utils.pathing.MoveResult.IMPOSSIBLE; + public class MovementDescend extends Movement { private int numTicks = 0; @@ -45,24 +51,111 @@ public class MovementDescend extends Movement { @Override protected double calculateCost(CalculationContext context) { - Block fromDown = BlockStateInterface.get(src.down()).getBlock(); + MoveResult result = cost(context, src.x, src.y, src.z, dest.x, dest.z); + if (result.destY != dest.y) { + return COST_INF; // doesn't apply to us, this position is a fall not a descend + } + return result.cost; + } + + public static MoveResult cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { + Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock(); if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { - return COST_INF; + return IMPOSSIBLE; } - if (!MovementHelper.canWalkOn(positionToPlace)) { - return COST_INF; + + double totalCost = 0; + IBlockState destDown = BlockStateInterface.get(destX, y - 1, destZ); + totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false); + if (totalCost >= COST_INF) { + return IMPOSSIBLE; } - Block tmp1 = BlockStateInterface.get(dest).getBlock(); - if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) { - return COST_INF; + totalCost += MovementHelper.getMiningDurationTicks(context, destX, y, destZ, false); + if (totalCost >= COST_INF) { + return IMPOSSIBLE; } + totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, true); // only the top block in the 3 we need to mine needs to consider the falling blocks above + if (totalCost >= COST_INF) { + return IMPOSSIBLE; + } + + // A + //SA + // A + // B + // C + // D + //if S is where you start, B needs to be air for a movementfall + //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)) { + return dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below); + } + + if (destDown.getBlock() == Blocks.LADDER || destDown.getBlock() == Blocks.VINE) { + return IMPOSSIBLE; + } + // we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel) double walk = WALK_OFF_BLOCK_COST; if (fromDown == Blocks.SOUL_SAND) { // use this ratio to apply the soul sand speed penalty to our 0.8 block distance walk = WALK_ONE_OVER_SOUL_SAND_COST; } - return walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST) + getTotalHardnessOfBlocksToBreak(context); + totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST); + return new MoveResult(destX, y - 1, destZ, totalCost); + } + + public static MoveResult dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below) { + if (frontBreak != 0 && BlockStateInterface.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 IMPOSSIBLE; + } + if (!MovementHelper.canWalkThrough(destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) { + return IMPOSSIBLE; + } + for (int fallHeight = 3; true; fallHeight++) { + int newY = y - fallHeight; + if (newY < 0) { + // when pathing in the end, where you could plausibly fall into the void + // this check prevents it from getting the block at y=-1 and crashing + return IMPOSSIBLE; + } + IBlockState ontoBlock = BlockStateInterface.get(destX, newY, destZ); + double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak; + if (ontoBlock.getBlock() == Blocks.WATER && !BlockStateInterface.isFlowing(ontoBlock)) { // TODO flowing check required here? + if (Baritone.settings().assumeWalkOnWater.get()) { + return IMPOSSIBLE; // TODO fix + } + // found a fall into water + return new MoveResult(destX, newY, destZ, tentativeCost); // TODO incorporate water swim up cost? + } + if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) { + return IMPOSSIBLE; + } + if (MovementHelper.canWalkThrough(destX, newY, destZ, ontoBlock)) { + continue; + } + if (!MovementHelper.canWalkOn(destX, newY, destZ, ontoBlock)) { + return IMPOSSIBLE; + } + if (MovementHelper.isBottomSlab(ontoBlock)) { + return IMPOSSIBLE; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect + } + if (context.hasWaterBucket() && fallHeight <= context.maxFallHeightBucket() + 1) { + return new MoveResult(destX, newY + 1, destZ, tentativeCost + context.placeBlockCost()); // this is the block we're falling onto, so dest is +1 + } + if (fallHeight <= context.maxFallHeightNoWater() + 1) { + // fallHeight = 4 means onto.up() is 3 blocks down, which is the max + return new MoveResult(destX, newY + 1, destZ, tentativeCost); + } else { + return IMPOSSIBLE; + } + } } @Override diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java index d092b66e..d1fe89a4 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java @@ -25,7 +25,6 @@ import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.Block; -import net.minecraft.block.BlockMagma; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; @@ -53,40 +52,44 @@ public class MovementDiagonal extends Movement { @Override protected double calculateCost(CalculationContext context) { - Block fromDown = BlockStateInterface.get(src.down()).getBlock(); + return cost(context, src.x, src.y, src.z, dest.x, dest.z); + } + + 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(); if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { return COST_INF; } - if (!MovementHelper.canWalkThrough(positionsToBreak[4]) || !MovementHelper.canWalkThrough(positionsToBreak[5])) { + IBlockState destInto = BlockStateInterface.get(destX, y, destZ); + if (!MovementHelper.canWalkThrough(destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(destX, y + 1, destZ)) { return COST_INF; } - BetterBlockPos destDown = dest.down(); - IBlockState destWalkOn = BlockStateInterface.get(destDown); - if (!MovementHelper.canWalkOn(destDown, destWalkOn)) { + IBlockState destWalkOn = BlockStateInterface.get(destX, y - 1, destZ); + if (!MovementHelper.canWalkOn(destX, y - 1, destZ, destWalkOn)) { return COST_INF; } double multiplier = WALK_ONE_BLOCK_COST; // For either possible soul sand, that affects half of our walking - if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) { + if (destWalkOn.getBlock() == Blocks.SOUL_SAND) { multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } if (fromDown == Blocks.SOUL_SAND) { multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } - Block cuttingOver1 = BlockStateInterface.get(positionsToBreak[2].down()).getBlock(); - if (cuttingOver1 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver1)) { + Block cuttingOver1 = BlockStateInterface.get(x, y - 1, destZ).getBlock(); + if (cuttingOver1 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver1)) { return COST_INF; } - Block cuttingOver2 = BlockStateInterface.get(positionsToBreak[4].down()).getBlock(); - if (cuttingOver2 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver2)) { + Block cuttingOver2 = BlockStateInterface.get(destX, y - 1, z).getBlock(); + if (cuttingOver2 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver2)) { return COST_INF; } - IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); - IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); - IBlockState pb2 = BlockStateInterface.get(positionsToBreak[2]); - IBlockState pb3 = BlockStateInterface.get(positionsToBreak[3]); - double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, true); - double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], pb2, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], pb3, true); + IBlockState pb0 = BlockStateInterface.get(x, y, destZ); + IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ); + IBlockState pb2 = BlockStateInterface.get(destX, y, z); + IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z); + double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false) + MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true); + double optionB = MovementHelper.getMiningDurationTicks(context, destX, y, z, pb2, false) + MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true); if (optionA != 0 && optionB != 0) { return COST_INF; } @@ -100,7 +103,7 @@ public class MovementDiagonal extends Movement { return COST_INF; } } - if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) { + if (BlockStateInterface.isWater(BlockStateInterface.getBlock(x, y, z)) || BlockStateInterface.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 diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java index b265ddd7..148dc3b3 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java @@ -43,17 +43,21 @@ public class MovementDownward extends Movement { @Override protected double calculateCost(CalculationContext context) { - if (!MovementHelper.canWalkOn(dest.down())) { + return cost(context, src.x, src.y, src.z); + } + + public static double cost(CalculationContext context, int x, int y, int z) { + if (!MovementHelper.canWalkOn(x, y - 2, z)) { return COST_INF; } - IBlockState d = BlockStateInterface.get(dest); + IBlockState d = BlockStateInterface.get(x, y - 1, z); Block td = d.getBlock(); boolean ladder = td == Blocks.LADDER || td == Blocks.VINE; if (ladder) { return LADDER_DOWN_ONE_COST; } else { // we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement - return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d, false); + return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, x, y - 1, z, d, false); } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java index a6a9e9f6..0f165f6f 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java @@ -18,19 +18,20 @@ package baritone.pathing.movement.movements; import baritone.Baritone; +import baritone.api.utils.Rotation; 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.MovementStatus; import baritone.pathing.movement.MovementState.MovementTarget; -import baritone.utils.*; +import baritone.utils.BlockStateInterface; +import baritone.utils.InputOverrideHandler; +import baritone.utils.RayTraceUtils; +import baritone.utils.Utils; import baritone.utils.pathing.BetterBlockPos; -import net.minecraft.block.Block; -import net.minecraft.block.BlockFalling; -import net.minecraft.block.state.IBlockState; +import baritone.utils.pathing.MoveResult; import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; @@ -48,58 +49,11 @@ public class MovementFall extends Movement { @Override protected double calculateCost(CalculationContext context) { - Block fromDown = BlockStateInterface.get(src.down()).getBlock(); - if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { - return COST_INF; + MoveResult result = MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z); + if (result.destY != dest.y) { + return COST_INF; // doesn't apply to us, this position is a descend not a fall } - IBlockState fallOnto = BlockStateInterface.get(dest.down()); - if (!MovementHelper.canWalkOn(dest.down(), fallOnto)) { - return COST_INF; - } - if (MovementHelper.isBottomSlab(fallOnto)) { - return COST_INF; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect - } - double placeBucketCost = 0.0; - boolean destIsWater = BlockStateInterface.isWater(dest); - if (!destIsWater && src.getY() - dest.getY() > context.maxFallHeightNoWater()) { - if (!context.hasWaterBucket()) { - return COST_INF; - } - if (src.getY() - dest.getY() > context.maxFallHeightBucket()) { - return COST_INF; - } - placeBucketCost = context.placeBlockCost(); - } - double frontThree = 0; - for (int i = 0; i < 3; i++) { - frontThree += MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false); - // don't include falling because we will check falling right after this, and if it's there it's COST_INF - if (frontThree >= COST_INF) { - return COST_INF; - } - } - if (BlockStateInterface.get(positionsToBreak[0].up()).getBlock() instanceof BlockFalling) { - return COST_INF; - } - for (int i = 3; i < positionsToBreak.length; i++) { - // TODO is this the right check here? - // MiningDurationTicks is all right, but shouldn't it be canWalkThrough instead? - // Lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage - // Same thing for falling through water... we can't actually do that - // And falling through signs is possible, but they do have a mining duration, right? - if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false) > 0) { - //can't break while falling - - if (i != positionsToBreak.length - 1 || !destIsWater) { - // if we're checking the very last block to mine - // and it's water (so this is a water fall) - // don't consider the cost of "mining" it - // (if assumeWalkOnWater is true, water isn't canWalkThrough) - return COST_INF; - } - } - } - return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontThree; + return result.cost; } @Override diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 0093539f..80382c67 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -27,7 +27,7 @@ import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; import baritone.utils.Utils; import baritone.utils.pathing.BetterBlockPos; -import net.minecraft.block.Block; +import baritone.utils.pathing.MoveResult; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; @@ -37,8 +37,10 @@ import net.minecraft.util.math.Vec3d; import java.util.Objects; +import static baritone.utils.pathing.MoveResult.IMPOSSIBLE; + public class MovementParkour extends Movement { - private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN}; + private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN}; private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{}; private final EnumFacing direction; @@ -48,79 +50,81 @@ public class MovementParkour extends Movement { super(src, src.offset(dir, dist), EMPTY); this.direction = dir; this.dist = dist; - super.override(costFromJumpDistance(dist)); } - public static MovementParkour generate(BetterBlockPos src, EnumFacing dir, CalculationContext context) { - // MUST BE KEPT IN SYNC WITH calculateCost + public static MovementParkour cost(CalculationContext context, BetterBlockPos src, EnumFacing direction) { + MoveResult res = cost(context, src.x, src.y, src.z, direction); + int dist = Math.abs(res.destX - src.x) + Math.abs(res.destZ - src.z); + return new MovementParkour(src, dist, direction); + } + + public static MoveResult cost(CalculationContext context, int x, int y, int z, EnumFacing dir) { if (!Baritone.settings().allowParkour.get()) { - return null; + return IMPOSSIBLE; } - IBlockState standingOn = BlockStateInterface.get(src.down()); + IBlockState standingOn = BlockStateInterface.get(x, y - 1, z); if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) { - return null; + return IMPOSSIBLE; } - BetterBlockPos adjBlock = src.down().offset(dir); - IBlockState adj = BlockStateInterface.get(adjBlock); + int xDiff = dir.getXOffset(); + int zDiff = dir.getZOffset(); + IBlockState adj = BlockStateInterface.get(x + xDiff, y - 1, z + zDiff); if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks - return null; + return IMPOSSIBLE; } - if (MovementHelper.canWalkOn(adjBlock, adj)) { // don't parkour if we could just traverse (for now) - return null; + if (MovementHelper.canWalkOn(x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up().offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y + 1, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up(2).offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y + 2, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up(2))) { - return null; + if (!MovementHelper.fullyPassable(x, y + 2, z)) { + return IMPOSSIBLE; } for (int i = 2; i <= (context.canSprint() ? 4 : 3); i++) { - BetterBlockPos dest = src.offset(dir, i); // TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly? - for (int y = 0; y < 4; y++) { - if (!MovementHelper.fullyPassable(dest.up(y))) { - return null; + for (int y2 = 0; y2 < 4; y2++) { + if (!MovementHelper.fullyPassable(x + xDiff * i, y + y2, z + zDiff * i)) { + return IMPOSSIBLE; } } - if (MovementHelper.canWalkOn(dest.down())) { - return new MovementParkour(src, i, dir); + if (MovementHelper.canWalkOn(x + xDiff * i, y - 1, z + zDiff * i)) { + return new MoveResult(x + xDiff * i, y, z + zDiff * i, costFromJumpDistance(i)); } } if (!context.canSprint()) { - return null; + return IMPOSSIBLE; } if (!Baritone.settings().allowParkourPlace.get()) { - return null; + return IMPOSSIBLE; } - BlockPos dest = src.offset(dir, 4); - BlockPos positionToPlace = dest.down(); - IBlockState toPlace = BlockStateInterface.get(positionToPlace); + int destX = x + 4 * xDiff; + int destZ = z + 4 * zDiff; + IBlockState toPlace = BlockStateInterface.get(destX, y - 1, destZ); if (!context.hasThrowaway()) { - return null; + return IMPOSSIBLE; } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) { - return null; + if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace)) { + return IMPOSSIBLE; } for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); - if (against1.up().equals(src.offset(dir, 3))) { // we can't turn around that fast + int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset(); + int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset(); + if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast continue; } - if (MovementHelper.canPlaceAgainst(against1)) { - // holy jesus we gonna do it - MovementParkour ret = new MovementParkour(src, 4, dir); - ret.override(costFromJumpDistance(4) + context.placeBlockCost()); - return ret; + if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) { + return new MoveResult(destX, y, destZ, costFromJumpDistance(i) + context.placeBlockCost()); } } - return null; + return IMPOSSIBLE; } private static double costFromJumpDistance(int dist) { @@ -139,54 +143,11 @@ public class MovementParkour extends Movement { @Override protected double calculateCost(CalculationContext context) { - // MUST BE KEPT IN SYNC WITH generate - if (!context.canSprint() && dist >= 4) { + MoveResult res = cost(context, src.x, src.y, src.z, direction); + if (res.destX != dest.x || res.destZ != dest.z) { return COST_INF; } - boolean placing = false; - if (!MovementHelper.canWalkOn(dest.down())) { - if (dist != 4) { - return COST_INF; - } - if (!Baritone.settings().allowParkourPlace.get()) { - return COST_INF; - } - BlockPos positionToPlace = dest.down(); - IBlockState toPlace = BlockStateInterface.get(positionToPlace); - if (!context.hasThrowaway()) { - return COST_INF; - } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) { - return COST_INF; - } - for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); - if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast - continue; - } - if (MovementHelper.canPlaceAgainst(against1)) { - // holy jesus we gonna do it - placing = true; - break; - } - } - } - Block walkOff = BlockStateInterface.get(src.down().offset(direction)).getBlock(); - if (MovementHelper.avoidWalkingInto(walkOff) && walkOff != Blocks.WATER && walkOff != Blocks.FLOWING_WATER) { - return COST_INF; - } - for (int i = 1; i <= 4; i++) { - BlockPos d = src.offset(direction, i); - for (int y = 0; y < (i == 1 ? 3 : 4); y++) { - if (!MovementHelper.fullyPassable(d.up(y))) { - return COST_INF; - } - } - if (d.equals(dest)) { - return costFromJumpDistance(i) + (placing ? context.placeBlockCost() : 0); - } - } - throw new IllegalStateException("invalid jump distance?"); + return res.cost; } @Override @@ -209,7 +170,7 @@ public class MovementParkour extends Movement { if (!MovementHelper.canWalkOn(dest.down())) { BlockPos positionToPlace = dest.down(); for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); + BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]); if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast continue; } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java index 4cdc2f05..be524185 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java @@ -17,13 +17,13 @@ package baritone.pathing.movement.movements; +import baritone.api.utils.Rotation; 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.Rotation; import baritone.utils.Utils; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.*; @@ -48,9 +48,13 @@ public class MovementPillar extends Movement { @Override protected double calculateCost(CalculationContext context) { - Block fromDown = BlockStateInterface.get(src).getBlock(); + return cost(context, src.x, src.y, src.z); + } + + public static double cost(CalculationContext context, int x, int y, int z) { + Block fromDown = BlockStateInterface.get(x, y, z).getBlock(); boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine; - IBlockState fromDownDown = BlockStateInterface.get(src.down()); + IBlockState fromDownDown = BlockStateInterface.get(x, y - 1, z); if (!ladder) { if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) { return COST_INF; @@ -61,28 +65,27 @@ public class MovementPillar extends Movement { } } } - if (!context.hasThrowaway() && !ladder) { - return COST_INF; - } if (fromDown instanceof BlockVine) { - if (getAgainst(src) == null) { + if (!hasAgainst(x, y, z)) { return COST_INF; } } - BlockPos toBreakPos = src.up(2); - IBlockState toBreak = BlockStateInterface.get(toBreakPos); + IBlockState toBreak = BlockStateInterface.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(dest).getBlock(); + srcUp = BlockStateInterface.get(x, y + 1, z).getBlock(); if (BlockStateInterface.isWater(srcUp)) { return LADDER_UP_ONE_COST; } } - double hardness = MovementHelper.getMiningDurationTicks(context, toBreakPos, toBreak, true); + if (!context.hasThrowaway() && !ladder) { + return COST_INF; + } + double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true); if (hardness >= COST_INF) { return COST_INF; } @@ -90,12 +93,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 { - BlockPos chkPos = src.up(3); - IBlockState check = BlockStateInterface.get(chkPos); + IBlockState check = BlockStateInterface.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(dest).getBlock(); + srcUp = BlockStateInterface.get(x, y + 1, z).getBlock(); } if (!(toBreakBlock instanceof BlockFalling) || !(srcUp instanceof BlockFalling)) { return COST_INF; @@ -120,6 +122,13 @@ 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 BlockPos getAgainst(BlockPos vine) { if (BlockStateInterface.get(vine.north()).isBlockNormalCube()) { return vine.north(); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index a2d64377..a16a50a1 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -18,6 +18,7 @@ package baritone.pathing.movement.movements; import baritone.Baritone; +import baritone.api.utils.Rotation; import baritone.behavior.LookBehaviorUtils; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; @@ -25,7 +26,6 @@ import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementState; import baritone.utils.BlockStateInterface; import baritone.utils.InputOverrideHandler; -import baritone.utils.Rotation; import baritone.utils.Utils; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.*; @@ -57,11 +57,15 @@ public class MovementTraverse extends Movement { @Override protected double calculateCost(CalculationContext context) { - IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); - IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); - IBlockState destOn = BlockStateInterface.get(positionToPlace); - Block srcDown = BlockStateInterface.getBlock(src.down()); - if (MovementHelper.canWalkOn(positionToPlace, destOn)) {//this is a walk, not a bridge + return cost(context, src.x, src.y, src.z, dest.x, dest.z); + } + + 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 double WC = WALK_ONE_BLOCK_COST; if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) { WC = WALK_ONE_IN_WATER_COST; @@ -73,11 +77,11 @@ public class MovementTraverse extends Movement { WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; } } - double hardness1 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, true); + double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true); if (hardness1 >= COST_INF) { return COST_INF; } - double hardness2 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, false); + double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false); if (hardness1 == 0 && hardness2 == 0) { if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) { // If there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing @@ -95,7 +99,7 @@ public class MovementTraverse extends Movement { if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) { return COST_INF; } - if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(positionToPlace, destOn)) { + 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) { return COST_INF; @@ -103,15 +107,21 @@ public class MovementTraverse extends Movement { if (!context.hasThrowaway()) { return COST_INF; } + double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb0, false); + if (hardness1 >= COST_INF) { + return COST_INF; + } + double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb1, true); + double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST; for (int i = 0; i < 4; i++) { - BlockPos against1 = dest.offset(HORIZONTALS[i]); - if (against1.equals(src)) { + int againstX = destX + HORIZONTALS[i].getXOffset(); + int againstZ = destZ + HORIZONTALS[i].getZOffset(); + if (againstX == x && againstZ == z) { continue; } - against1 = against1.down(); - if (MovementHelper.canPlaceAgainst(against1)) { - return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context); + if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) { + return WC + context.placeBlockCost() + hardness1 + hardness2; } } if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) { @@ -121,7 +131,7 @@ public class MovementTraverse extends Movement { return COST_INF; // this is obviously impossible } WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking - return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context); + return WC + context.placeBlockCost() + hardness1 + hardness2; } return COST_INF; // Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock()); @@ -155,8 +165,8 @@ public class MovementTraverse extends Movement { // combine the yaw to the center of the destination, and the pitch to the specific block we're trying to break // it's safe to do this since the two blocks we break (in a traverse) are right on top of each other and so will have the same yaw - float yawToDest = Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(dest, world())).getFirst(); - float pitchToBreak = state.getTarget().getRotation().get().getSecond(); + float yawToDest = Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(dest, world())).getYaw(); + float pitchToBreak = state.getTarget().getRotation().get().getPitch(); state.setTarget(new MovementState.MovementTarget(new Rotation(yawToDest, pitchToBreak), true)); return state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); diff --git a/src/main/java/baritone/pathing/path/CutoffPath.java b/src/main/java/baritone/pathing/path/CutoffPath.java index 295f3830..e517452e 100644 --- a/src/main/java/baritone/pathing/path/CutoffPath.java +++ b/src/main/java/baritone/pathing/path/CutoffPath.java @@ -17,7 +17,7 @@ package baritone.pathing.path; -import baritone.pathing.goals.Goal; +import baritone.api.pathing.goals.Goal; import baritone.pathing.movement.Movement; import baritone.utils.pathing.BetterBlockPos; diff --git a/src/main/java/baritone/pathing/path/IPath.java b/src/main/java/baritone/pathing/path/IPath.java index 59cb8cac..0701abf6 100644 --- a/src/main/java/baritone/pathing/path/IPath.java +++ b/src/main/java/baritone/pathing/path/IPath.java @@ -18,7 +18,7 @@ package baritone.pathing.path; import baritone.Baritone; -import baritone.pathing.goals.Goal; +import baritone.api.pathing.goals.Goal; import baritone.pathing.movement.Movement; import baritone.utils.Helper; import baritone.utils.Utils; diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index 815d6d1b..e8e74c7d 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -19,6 +19,7 @@ package baritone.pathing.path; import baritone.Baritone; import baritone.api.event.events.TickEvent; +import baritone.api.pathing.movement.ActionCosts; import baritone.pathing.movement.*; import baritone.pathing.movement.movements.*; import baritone.utils.BlockStateInterface; @@ -94,6 +95,7 @@ public class PathExecutor implements Helper { if (pathPosition == 0 && whereAmI.equals(whereShouldIBe.up()) && Math.abs(player().motionY) < 0.1 && !(path.movements().get(0) instanceof MovementAscend) && !(path.movements().get(0) instanceof MovementPillar)) { // avoid the Wrong Y coordinate bug + // TODO add a timer here new MovementDownward(whereAmI, whereShouldIBe).update(); return false; } diff --git a/src/main/java/baritone/utils/BaritoneAutoTest.java b/src/main/java/baritone/utils/BaritoneAutoTest.java new file mode 100644 index 00000000..729754d5 --- /dev/null +++ b/src/main/java/baritone/utils/BaritoneAutoTest.java @@ -0,0 +1,123 @@ +/* + * 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.api.event.events.TickEvent; +import baritone.api.event.listener.AbstractGameEventListener; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalBlock; +import baritone.behavior.PathingBehavior; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.settings.GameSettings; +import net.minecraft.client.tutorial.TutorialSteps; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.GameType; +import net.minecraft.world.WorldSettings; +import net.minecraft.world.WorldType; + +public class BaritoneAutoTest implements AbstractGameEventListener, Helper { + + public static final BaritoneAutoTest INSTANCE = new BaritoneAutoTest(); + + private BaritoneAutoTest() {} + + public static final boolean ENABLE_AUTO_TEST = true; + private static final long TEST_SEED = -928872506371745L; + private static final BlockPos STARTING_POSITION = new BlockPos(0, 65, 0); + private static final Goal GOAL = new GoalBlock(69, 121, 420); + private static final int MAX_TICKS = 3500; + + /** + * Called right after the {@link GameSettings} object is created in the {@link Minecraft} instance. + */ + public void onPreInit() { + System.out.println("Optimizing Game Settings"); + + GameSettings s = mc.gameSettings; + s.limitFramerate = 20; + s.mipmapLevels = 0; + s.particleSetting = 2; + s.overrideWidth = 128; + s.overrideHeight = 128; + s.heldItemTooltips = false; + s.entityShadows = false; + s.chatScale = 0.0F; + s.ambientOcclusion = 0; + s.clouds = 0; + s.fancyGraphics = false; + s.tutorialStep = TutorialSteps.NONE; + s.hideGUI = true; + s.fovSetting = 30.0F; + } + + @Override + public void onTick(TickEvent event) { + + // If we're on the main menu then create the test world and launch the integrated server + if (mc.currentScreen instanceof GuiMainMenu) { + System.out.println("Beginning Baritone automatic test routine"); + mc.displayGuiScreen(null); + WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.getByName("survival"), true, false, WorldType.DEFAULT); + mc.launchIntegratedServer("BaritoneAutoTest", "BaritoneAutoTest", worldsettings); + } + + // If the integrated server is launched and the world has initialized, set the spawn point + // to our defined starting position + if (mc.getIntegratedServer() != null && mc.getIntegratedServer().worlds[0] != null) { + mc.getIntegratedServer().worlds[0].setSpawnPoint(STARTING_POSITION); + mc.getIntegratedServer().worlds[0].getGameRules().setOrCreateGameRule("spawnRadius", "0"); + } + + if (event.getType() == TickEvent.Type.IN) { // If we're in-game + + // Force the integrated server to share the world to LAN so that + // the ingame pause menu gui doesn't actually pause our game + if (mc.isSingleplayer() && !mc.getIntegratedServer().getPublic()) { + mc.getIntegratedServer().shareToLAN(GameType.getByName("survival"), false); + } + + // For the first 200 ticks, wait for the world to generate + if (event.getCount() < 200) { + System.out.println("Waiting for world to generate... " + event.getCount()); + return; + } + + // Print out an update of our position every 5 seconds + if (event.getCount() % 100 == 0) { + System.out.println(playerFeet() + " " + event.getCount()); + } + + // Setup Baritone's pathing goal and (if needed) begin pathing + PathingBehavior.INSTANCE.setGoal(GOAL); + PathingBehavior.INSTANCE.path(); + + // If we have reached our goal, print a message and safely close the game + if (GOAL.isInGoal(playerFeet())) { + System.out.println("Successfully pathed to " + playerFeet() + " in " + event.getCount() + " ticks"); + mc.shutdown(); + } + + // If we have exceeded the expected number of ticks to complete the pathing + // task, then throw an IllegalStateException to cause the build to fail + if (event.getCount() > MAX_TICKS) { + throw new IllegalStateException("took too long"); + } + } + } +} diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java index 3ccc56f9..1bc4a44a 100644 --- a/src/main/java/baritone/utils/BlockBreakHelper.java +++ b/src/main/java/baritone/utils/BlockBreakHelper.java @@ -46,7 +46,9 @@ public final class BlockBreakHelper implements Helper { } public static void stopBreakingBlock() { - mc.playerController.resetBlockRemoving(); + if (mc.playerController != null) { + mc.playerController.resetBlockRemoving(); + } lastBlock = null; } } diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index d037b148..774d08e9 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -60,6 +60,7 @@ public class BlockStateInterface implements Helper { // if it's the same chunk as last time // we can just skip the mc.world.getChunk lookup // which is a Long2ObjectOpenHashMap.get + // see issue #113 if (cached != null && cached.x == x >> 4 && cached.z == z >> 4) { numTimesChunkSucceeded++; return cached.getBlockState(x, y, z); @@ -92,6 +93,32 @@ public class BlockStateInterface implements Helper { return type; } + public static 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); + if (prevChunk.isLoaded()) { + prev = prevChunk; + return true; + } + CachedRegion prevRegion = prevCached; + 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) { + return false; + } + prevRegion = world.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; @@ -101,6 +128,9 @@ public class BlockStateInterface implements Helper { 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 diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java index 6cd2655a..ee58fd60 100644 --- a/src/main/java/baritone/utils/ExampleBaritoneControl.java +++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java @@ -18,23 +18,20 @@ package baritone.utils; import baritone.Baritone; -import baritone.Settings; -import baritone.api.behavior.Behavior; +import baritone.api.Settings; +import baritone.api.cache.IWaypoint; import baritone.api.event.events.ChatEvent; +import baritone.api.pathing.goals.*; +import baritone.api.pathing.movement.ActionCosts; +import baritone.behavior.Behavior; import baritone.behavior.FollowBehavior; import baritone.behavior.MineBehavior; import baritone.behavior.PathingBehavior; import baritone.cache.ChunkPacker; import baritone.cache.Waypoint; import baritone.cache.WorldProvider; -import baritone.pathing.calc.AStarPathFinder; import baritone.pathing.calc.AbstractNodeCostSearch; -import baritone.pathing.goals.*; -import baritone.pathing.movement.ActionCosts; -import baritone.pathing.movement.CalculationContext; -import baritone.pathing.movement.Movement; -import baritone.pathing.movement.MovementHelper; -import baritone.utils.pathing.BetterBlockPos; +import baritone.pathing.movement.*; import net.minecraft.block.Block; import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.entity.Entity; @@ -43,6 +40,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.Chunk; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ExampleBaritoneControl extends Behavior implements Helper { @@ -185,7 +184,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { Chunk chunk = cli.getLoadedChunk(x, z); if (chunk != null) { count++; - WorldProvider.INSTANCE.getCurrentWorld().cache.queueForPacking(chunk); + WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().queueForPacking(chunk); } } } @@ -208,7 +207,11 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return; } if (msg.equals("forcecancel")) { + MineBehavior.INSTANCE.cancel(); + FollowBehavior.INSTANCE.cancel(); + PathingBehavior.INSTANCE.cancel(); AbstractNodeCostSearch.forceCancel(); + PathingBehavior.INSTANCE.forceCancel(); event.cancel(); logDirect("ok force canceled"); return; @@ -269,20 +272,20 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return; } if (msg.equals("reloadall")) { - WorldProvider.INSTANCE.getCurrentWorld().cache.reloadAllFromDisk(); + WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().reloadAllFromDisk(); logDirect("ok"); event.cancel(); return; } if (msg.equals("saveall")) { - WorldProvider.INSTANCE.getCurrentWorld().cache.save(); + WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().save(); logDirect("ok"); event.cancel(); return; } if (msg.startsWith("find")) { String blockType = msg.substring(4).trim(); - LinkedList locs = WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(blockType, 1, 4); + LinkedList locs = WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, 4); logDirect("Have " + locs.size() + " locations"); for (BlockPos pos : locs) { Block actually = BlockStateInterface.get(pos).getBlock(); @@ -297,8 +300,9 @@ public class ExampleBaritoneControl extends Behavior implements Helper { String[] blockTypes = msg.substring(4).trim().split(" "); try { int quantity = Integer.parseInt(blockTypes[1]); - ChunkPacker.stringToBlock(blockTypes[0]).hashCode(); - MineBehavior.INSTANCE.mine(quantity, blockTypes[0]); + Block block = ChunkPacker.stringToBlock(blockTypes[0]); + Objects.requireNonNull(block); + MineBehavior.INSTANCE.mine(quantity, block); logDirect("Will mine " + quantity + " " + blockTypes[0]); event.cancel(); return; @@ -339,22 +343,38 @@ public class ExampleBaritoneControl extends Behavior implements Helper { event.cancel(); return; } - Set waypoints = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getByTag(tag); + Set waypoints = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getByTag(tag); // might as well show them from oldest to newest - List sorted = new ArrayList<>(waypoints); - sorted.sort(Comparator.comparingLong(Waypoint::creationTimestamp)); + List sorted = new ArrayList<>(waypoints); + sorted.sort(Comparator.comparingLong(IWaypoint::getCreationTimestamp)); logDirect("Waypoints under tag " + tag + ":"); - for (Waypoint waypoint : sorted) { + for (IWaypoint waypoint : sorted) { logDirect(waypoint.toString()); } event.cancel(); return; } if (msg.startsWith("save")) { - String name = msg.substring(4).trim(); - WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint(name, Waypoint.Tag.USER, playerFeet())); - logDirect("Saved user defined tag under name '" + name + "'. Say 'goto user' to set goal, say 'list user' to list."); event.cancel(); + String name = msg.substring(4).trim(); + BlockPos pos = playerFeet(); + if (name.contains(" ")) { + logDirect("Name contains a space, assuming it's in the format 'save waypointName X Y Z'"); + String[] parts = name.split(" "); + if (parts.length != 4) { + logDirect("Unable to parse, expected four things"); + return; + } + try { + pos = new BlockPos(Integer.parseInt(parts[1]), Integer.parseInt(parts[2]), Integer.parseInt(parts[3])); + } catch (NumberFormatException ex) { + logDirect("Unable to parse coordinate integers"); + return; + } + name = parts[0]; + } + WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint(name, Waypoint.Tag.USER, pos)); + logDirect("Saved user defined position " + pos + " under name '" + name + "'. Say 'goto user' to set goal, say 'list user' to list."); return; } if (msg.startsWith("goto")) { @@ -364,31 +384,37 @@ public class ExampleBaritoneControl extends Behavior implements Helper { waypointType = waypointType.substring(0, waypointType.length() - 1); } Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType); + IWaypoint waypoint; if (tag == null) { String mining = waypointType; Block block = ChunkPacker.stringToBlock(mining); //logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); event.cancel(); if (block == null) { - logDirect("No locations for " + mining + " known, cancelling"); + waypoint = WorldProvider.INSTANCE.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; + } + } else { + List locs = MineBehavior.INSTANCE.scanFor(Collections.singletonList(block), 64); + if (locs.isEmpty()) { + logDirect("No locations for " + mining + " known, cancelling"); + return; + } + PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalGetToBlock::new).toArray(Goal[]::new))); + PathingBehavior.INSTANCE.path(); return; } - List locs = MineBehavior.scanFor(Collections.singletonList(block), 64); - if (locs.isEmpty()) { - logDirect("No locations for " + mining + " known, cancelling"); + } else { + waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(tag); + if (waypoint == null) { + logDirect("None saved for tag " + tag); + event.cancel(); return; } - PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalGetToBlock::new).toArray(Goal[]::new))); - PathingBehavior.INSTANCE.path(); - return; } - Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(tag); - if (waypoint == null) { - logDirect("None saved for tag " + tag); - event.cancel(); - return; - } - Goal goal = new GoalBlock(waypoint.location); + Goal goal = new GoalBlock(waypoint.getLocation()); PathingBehavior.INSTANCE.setGoal(goal); if (!PathingBehavior.INSTANCE.path()) { if (!goal.isInGoal(playerFeet())) { @@ -399,7 +425,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return; } if (msg.equals("spawn") || msg.equals("bed")) { - Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(Waypoint.Tag.BED); + IWaypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.BED); if (waypoint == null) { BlockPos spawnPoint = player().getBedLocation(); // for some reason the default spawnpoint is underground sometimes @@ -407,7 +433,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { logDirect("spawn not saved, defaulting to world spawn. set goal to " + goal); PathingBehavior.INSTANCE.setGoal(goal); } else { - Goal goal = new GoalBlock(waypoint.location); + Goal goal = new GoalBlock(waypoint.getLocation()); PathingBehavior.INSTANCE.setGoal(goal); logDirect("Set goal to most recent bed " + goal); } @@ -415,17 +441,17 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return; } if (msg.equals("sethome")) { - WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("", Waypoint.Tag.HOME, playerFeet())); + WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("", Waypoint.Tag.HOME, playerFeet())); logDirect("Saved. Say home to set goal."); event.cancel(); return; } if (msg.equals("home")) { - Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(Waypoint.Tag.HOME); + IWaypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(Waypoint.Tag.HOME); if (waypoint == null) { logDirect("home not saved"); } else { - Goal goal = new GoalBlock(waypoint.location); + Goal goal = new GoalBlock(waypoint.getLocation()); PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.path(); logDirect("Going to saved home " + goal); @@ -434,8 +460,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper { return; } if (msg.equals("costs")) { - Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext()); - List moves = new ArrayList<>(Arrays.asList(movements)); + List moves = Stream.of(Moves.values()).map(x -> x.apply0(playerFeet())).collect(Collectors.toCollection(ArrayList::new)); while (moves.contains(null)) { moves.remove(null); } diff --git a/src/main/java/baritone/utils/Helper.java b/src/main/java/baritone/utils/Helper.java index 9924d0bf..a0ffdb96 100755 --- a/src/main/java/baritone/utils/Helper.java +++ b/src/main/java/baritone/utils/Helper.java @@ -18,6 +18,7 @@ package baritone.utils; import baritone.Baritone; +import baritone.api.utils.Rotation; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.BlockSlab; import net.minecraft.client.Minecraft; @@ -34,6 +35,11 @@ import net.minecraft.util.text.TextFormatting; */ public interface Helper { + /** + * Instance of {@link Helper}. Used for static-context reference. + */ + Helper HELPER = new Helper() {}; + ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format( "%s[%sBaritone%s]%s", TextFormatting.DARK_PURPLE, @@ -98,9 +104,4 @@ public interface Helper { component.appendSibling(new TextComponentString(" " + message)); Baritone.settings().logger.get().accept(component); } - - default void addToChat(ITextComponent msg) { - mc.ingameGUI.getChatGUI().printChatMessage(msg); - } - } diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index 86f49e5e..a66bc0ae 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -18,12 +18,12 @@ package baritone.utils; import baritone.Baritone; -import baritone.pathing.goals.Goal; -import baritone.pathing.goals.GoalComposite; -import baritone.pathing.goals.GoalTwoBlocks; -import baritone.pathing.goals.GoalXZ; +import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalComposite; +import baritone.api.pathing.goals.GoalTwoBlocks; +import baritone.api.pathing.goals.GoalXZ; import baritone.pathing.path.IPath; -import baritone.utils.interfaces.IGoalRenderPos; +import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; diff --git a/src/main/java/baritone/utils/RayTraceUtils.java b/src/main/java/baritone/utils/RayTraceUtils.java index d859ae4c..b313f1fe 100644 --- a/src/main/java/baritone/utils/RayTraceUtils.java +++ b/src/main/java/baritone/utils/RayTraceUtils.java @@ -17,6 +17,7 @@ package baritone.utils; +import baritone.api.utils.Rotation; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; @@ -30,6 +31,18 @@ public final class RayTraceUtils implements Helper { 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; @@ -48,6 +61,14 @@ public final class RayTraceUtils implements Helper { 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 + * entity is in the way or not. The local player's block reach distance will be used. + * + * @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); diff --git a/src/main/java/baritone/utils/Utils.java b/src/main/java/baritone/utils/Utils.java index 8a63347a..0de61461 100755 --- a/src/main/java/baritone/utils/Utils.java +++ b/src/main/java/baritone/utils/Utils.java @@ -17,6 +17,7 @@ package baritone.utils; +import baritone.api.utils.Rotation; import net.minecraft.block.BlockFire; import net.minecraft.block.state.IBlockState; import net.minecraft.client.entity.EntityPlayerSP; @@ -26,6 +27,8 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import static baritone.utils.Helper.HELPER; + /** * @author Brady * @since 8/1/2018 12:56 AM @@ -96,10 +99,7 @@ public final class Utils { } public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) { - return new Rotation( - MathHelper.wrapDegrees(target.getFirst() - current.getFirst()) + current.getFirst(), - MathHelper.wrapDegrees(target.getSecond() - current.getSecond()) + current.getSecond() - ); + return target.subtract(current).normalize().add(current); } public static Vec3d vec3dFromBlockPos(BlockPos orig) { @@ -114,12 +114,12 @@ public final class Utils { } public static double playerDistanceToCenter(BlockPos pos) { - EntityPlayerSP player = (new Helper() {}).player(); + EntityPlayerSP player = HELPER.player(); return distanceToCenter(pos, player.posX, player.posY, player.posZ); } public static double playerFlatDistanceToCenter(BlockPos pos) { - EntityPlayerSP player = (new Helper() {}).player(); + EntityPlayerSP player = HELPER.player(); return distanceToCenter(pos, player.posX, pos.getY() + 0.5, player.posZ); } diff --git a/src/main/java/baritone/utils/pathing/BetterBlockPos.java b/src/main/java/baritone/utils/pathing/BetterBlockPos.java index 41c99b30..5e8682c9 100644 --- a/src/main/java/baritone/utils/pathing/BetterBlockPos.java +++ b/src/main/java/baritone/utils/pathing/BetterBlockPos.java @@ -17,6 +17,7 @@ package baritone.utils.pathing; +import baritone.pathing.calc.AbstractNodeCostSearch; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; @@ -51,22 +52,7 @@ public final class BetterBlockPos extends BlockPos { this.x = x; this.y = y; this.z = z; - /* - * This is the hashcode implementation of Vec3i, the superclass of BlockPos - * - * public int hashCode() { - * return (this.getY() + this.getZ() * 31) * 31 + this.getX(); - * } - * - * That is terrible and has tons of collisions and makes the HashMap terribly inefficient. - * - * That's why we grab out the X, Y, Z and calculate our own hashcode - */ - long hash = 3241; - hash = 3457689L * hash + x; - hash = 8734625L * hash + y; - hash = 2873465L * hash + z; - this.hashCode = hash; + this.hashCode = AbstractNodeCostSearch.posHash(x, y, z); } public BetterBlockPos(double x, double y, double z) { @@ -129,7 +115,7 @@ public final class BetterBlockPos extends BlockPos { @Override public BetterBlockPos down(int amt) { // see comment in up() - return new BetterBlockPos(x, y - amt, z); + return amt == 0 ? this : new BetterBlockPos(x, y - amt, z); } @Override @@ -140,7 +126,50 @@ public final class BetterBlockPos extends BlockPos { @Override public BetterBlockPos offset(EnumFacing dir, int dist) { + if (dist == 0) { + return this; + } Vec3i vec = dir.getDirectionVec(); return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist); } + + @Override + public BetterBlockPos north() { + return new BetterBlockPos(x, y, z - 1); + } + + @Override + public BetterBlockPos north(int amt) { + return amt == 0 ? this : new BetterBlockPos(x, y, z - amt); + } + + @Override + public BetterBlockPos south() { + return new BetterBlockPos(x, y, z + 1); + } + + @Override + public BetterBlockPos south(int amt) { + return amt == 0 ? this : new BetterBlockPos(x, y, z + amt); + } + + @Override + public BetterBlockPos east() { + return new BetterBlockPos(x + 1, y, z); + } + + @Override + public BetterBlockPos east(int amt) { + return amt == 0 ? this : new BetterBlockPos(x + amt, y, z); + } + + @Override + public BetterBlockPos west() { + return new BetterBlockPos(x - 1, y, z); + } + + @Override + public BetterBlockPos west(int amt) { + return amt == 0 ? this : new BetterBlockPos(x - amt, y, z); + } } diff --git a/src/main/java/baritone/utils/pathing/MoveResult.java b/src/main/java/baritone/utils/pathing/MoveResult.java new file mode 100644 index 00000000..8478a617 --- /dev/null +++ b/src/main/java/baritone/utils/pathing/MoveResult.java @@ -0,0 +1,40 @@ +/* + * 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 static baritone.api.pathing.movement.ActionCosts.COST_INF; + +/** + * The result of a calculated movement, with destination x, y, z, and the cost of performing the movement + * + * @author leijurv + */ +public final class MoveResult { + public static final MoveResult IMPOSSIBLE = new MoveResult(0, 0, 0, COST_INF); + public final int destX; + public final int destY; + public final int destZ; + public final double cost; + + public MoveResult(int x, int y, int z, double cost) { + this.destX = x; + this.destY = y; + this.destZ = z; + this.cost = cost; + } +} diff --git a/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java b/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java index aebff976..8cc0bec7 100644 --- a/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java +++ b/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java @@ -17,10 +17,8 @@ package baritone.pathing.calc.openset; +import baritone.api.pathing.goals.Goal; import baritone.pathing.calc.PathNode; -import baritone.pathing.goals.Goal; -import baritone.utils.pathing.BetterBlockPos; -import net.minecraft.util.math.BlockPos; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -91,14 +89,14 @@ public class OpenSetsTest { // can't use an existing goal // because they use Baritone.settings() // and we can't do that because Minecraft itself isn't initted - PathNode pn = new PathNode(new BetterBlockPos(0, 0, 0), new Goal() { + PathNode pn = new PathNode(0, 0, 0, new Goal() { @Override - public boolean isInGoal(BlockPos pos) { + public boolean isInGoal(int x, int y, int z) { return false; } @Override - public double heuristic(BlockPos pos) { + public double heuristic(int x, int y, int z) { return 0; } }); diff --git a/src/test/java/baritone/pathing/goals/GoalGetToBlockTest.java b/src/test/java/baritone/pathing/goals/GoalGetToBlockTest.java index 2fa7f954..6234e050 100644 --- a/src/test/java/baritone/pathing/goals/GoalGetToBlockTest.java +++ b/src/test/java/baritone/pathing/goals/GoalGetToBlockTest.java @@ -17,6 +17,7 @@ package baritone.pathing.goals; +import baritone.api.pathing.goals.GoalGetToBlock; import net.minecraft.util.math.BlockPos; import org.junit.Test; diff --git a/src/test/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest.java b/src/test/java/baritone/pathing/movement/ActionCostsTest.java similarity index 92% rename from src/test/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest.java rename to src/test/java/baritone/pathing/movement/ActionCostsTest.java index 15291bbe..a3108c59 100644 --- a/src/test/java/baritone/pathing/movement/ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest.java +++ b/src/test/java/baritone/pathing/movement/ActionCostsTest.java @@ -19,10 +19,10 @@ package baritone.pathing.movement; import org.junit.Test; -import static baritone.pathing.movement.ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.*; +import static baritone.api.pathing.movement.ActionCosts.*; import static org.junit.Assert.assertEquals; -public class ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest { +public class ActionCostsTest { @Test public void testFallNBlocksCost() { assertEquals(FALL_N_BLOCKS_COST.length, 257); // Fall 0 blocks through fall 256 blocks diff --git a/src/test/java/baritone/utils/pathing/BetterBlockPosTest.java b/src/test/java/baritone/utils/pathing/BetterBlockPosTest.java index 2f0ab688..13b76c73 100644 --- a/src/test/java/baritone/utils/pathing/BetterBlockPosTest.java +++ b/src/test/java/baritone/utils/pathing/BetterBlockPosTest.java @@ -17,14 +17,17 @@ package baritone.utils.pathing; +import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import org.junit.Test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class BetterBlockPosTest { - @Test + // disabled since this is a benchmark, not really a test. also including it makes the tests take 50 seconds for no reason + /*@Test public void benchMulti() { System.out.println("Benching up()"); for (int i = 0; i < 10; i++) { @@ -37,7 +40,40 @@ public class BetterBlockPosTest { benchN(); assertTrue(i<10); } + }*/ + /** + * Make sure BetterBlockPos behaves just like BlockPos + */ + @Test + public void testSimple() { + BlockPos pos = new BlockPos(1, 2, 3); + BetterBlockPos better = new BetterBlockPos(1, 2, 3); + assertEquals(pos, better); + assertEquals(pos.up(), better.up()); + assertEquals(pos.down(), better.down()); + assertEquals(pos.north(), better.north()); + assertEquals(pos.south(), better.south()); + assertEquals(pos.east(), better.east()); + assertEquals(pos.west(), better.west()); + for (EnumFacing dir : EnumFacing.values()) { + assertEquals(pos.offset(dir), better.offset(dir)); + assertEquals(pos.offset(dir, 0), pos); + assertEquals(better.offset(dir, 0), better); + for (int i = -10; i < 10; i++) { + assertEquals(pos.offset(dir, i), better.offset(dir, i)); + } + assertTrue(better.offset(dir, 0) == better); + } + for (int i = -10; i < 10; i++) { + assertEquals(pos.up(i), better.up(i)); + assertEquals(pos.down(i), better.down(i)); + assertEquals(pos.north(i), better.north(i)); + assertEquals(pos.south(i), better.south(i)); + assertEquals(pos.east(i), better.east(i)); + assertEquals(pos.west(i), better.west(i)); + } + assertTrue(better.offset(null, 0) == better); } public void benchOne() { diff --git a/src/test/java/baritone/utils/pathing/PathingBlockTypeTest.java b/src/test/java/baritone/utils/pathing/PathingBlockTypeTest.java new file mode 100644 index 00000000..1582b66f --- /dev/null +++ b/src/test/java/baritone/utils/pathing/PathingBlockTypeTest.java @@ -0,0 +1,32 @@ +/* + * 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 org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class PathingBlockTypeTest { + @Test + public void testBits() { + for (PathingBlockType type : PathingBlockType.values()) { + boolean[] bits = type.getBits(); + assertTrue(type == PathingBlockType.fromBits(bits[0], bits[1])); + } + } +} \ No newline at end of file