This commit is contained in:
Leijurv
2018-09-26 13:45:00 -07:00
94 changed files with 2880 additions and 991 deletions
+27
View File
@@ -1 +1,28 @@
language: java 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
+28
View File
@@ -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
+11 -8
View File
@@ -11,9 +11,12 @@ There are some basic steps to getting Baritone setup with Impact.
## Acquiring a build of Baritone ## Acquiring a build of Baritone
There are 3 methods of acquiring a build of Baritone (While it is still in development) There are 3 methods of acquiring a build of Baritone (While it is still in development)
### Official Build (Not always up to date) ### Official Release (Not always up to date)
Download the "official" jar (as of commit <a href="https://github.com/cabaletta/baritone/commit/2e63ac41d9b22e4ee0a62f2bd29974e43e2071a1">2e63ac4</a>, https://github.com/cabaletta/baritone/releases
built on September 19) from <a href="https://www.dropbox.com/s/imc6xwwpwsh3i0y/baritone-1.0.0.jar?dl=0">here</a>.
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 ### Building Baritone yourself
There are a few steps to this There are a few steps to this
@@ -23,7 +26,7 @@ There are a few steps to this
command line command line
- Windows: ``gradlew build`` - Windows: ``gradlew build``
- Mac/Linux: ``./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 ### Cutting Edge Release
If you want to trust @Plutie#9079, you can download an automatically generated build of the latest commit 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`` - Create 3 new subdirectories starting from ``libraries``
- ``cabaletta`` - ``cabaletta``
- ``baritone`` - ``baritone``
- ``1.0.0`` - ``X.Y.Z``
- Copy the build of Baritone that was acquired earlier, and place it into the ``1.0.0`` folder - Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder
- The full path should look like ``<Minecraft>/libraries/cabaletta/baritone/1.0.0/baritone-1.0.0.jar`` - The full path should look like ``<Minecraft>/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar``
## Modifying the Impact Profile JSON to run baritone ## Modifying the Impact Profile JSON to run baritone
The final step is "registering" the Baritone library with Impact, so that it loads on launch. 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. - 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. - Now find the ``"minecraftArguments": "..."`` text near the top.
+17 -13
View File
@@ -3,15 +3,19 @@
[![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE) [![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&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/7150d8ccf6094057b1782aa7a8f92d7d)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;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.
<a href="https://github.com/cabaletta/baritone/blob/master/FEATURES.md">Features</a>
<a href="https://github.com/cabaletta/baritone/blob/master/IMPACT.md">Baritone + Impact</a>
Unofficial Jenkins: [![Build Status](https://plutiejenkins.leijurv.com/job/baritone/badge/icon)](https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/) 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 # Setup
## IntelliJ's Gradle UI ## IntelliJ's Gradle UI
@@ -38,18 +42,18 @@ $ gradlew genIntellijRuns
``` ```
# Chat control # Chat control
<a href="https://github.com/cabaletta/baritone/blob/master/src/main/java/baritone/utils/ExampleBaritoneControl.java">Defined here</a> [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. 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 # API example
``` ```
Baritone.settings().allowSprint.value = true; BaritoneAPI.getSettings().allowSprint.value = true;
Baritone.settings().pathTimeoutMS.value = 2000L; BaritoneAPI.getSettings().pathTimeoutMS.value = 2000L;
PathingBehavior.INSTANCE.setGoal(new GoalXZ(10000, 20000)); BaritoneAPI.getPathingBehavior().setGoal(new GoalXZ(10000, 20000));
PathingBehavior.INSTANCE.path(); BaritoneAPI.getPathingBehavior().path();
``` ```
# FAQ # FAQ
@@ -60,7 +64,7 @@ Sure! (As long as usage is in compliance with the LGPL 3 License)
## How is it so fast? ## How is it so fast?
Magic Magic. (Hours of [Leijurv](https://github.com/leijurv) enduring excruciating pain)
## Why is it called Baritone? ## Why is it called Baritone?
+1 -1
View File
@@ -16,7 +16,7 @@
*/ */
group 'baritone' group 'baritone'
version '1.0.0' version '0.0.3'
buildscript { buildscript {
repositories { repositories {
+30
View File
@@ -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 ..
+11 -15
View File
@@ -1,28 +1,28 @@
-injars baritone-1.0.0.jar -injars baritone-0.0.3.jar
-outjars Obfuscated -outjars Obfuscated
-keepattributes Signature -keepattributes Signature
-keepattributes *Annotation* -keepattributes *Annotation*
-optimizationpasses 20 -optimizationpasses 5
-verbose -verbose
-allowaccessmodification # anything not kept can be changed from public to private and inlined etc -allowaccessmodification # anything not kept can be changed from public to private and inlined etc
-overloadaggressively -overloadaggressively
-dontusemixedcaseclassnames -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 -flattenpackagehierarchy
-repackageclasses 'baritone' -repackageclasses 'baritone'
#-keep class baritone.behavior.** { *; } #-keep class baritone.behavior.** { *; }
#-keep class baritone.api.** { *; } -keep class baritone.api.** { *; }
#-keep class baritone.* { *; } #-keep class baritone.* { *; }
#-keep class baritone.pathing.goals.** { *; } #-keep class baritone.pathing.goals.** { *; }
# setting names are reflected from field names, so keep field names # setting names are reflected from field names, so keep field names
-keepclassmembers class baritone.Settings { -keepclassmembers class baritone.api.Settings {
public <fields>; public <fields>;
} }
@@ -30,9 +30,9 @@
-keep class baritone.launch.** { *; } -keep class baritone.launch.** { *; }
# copy all necessary libraries into tempLibraries to build # 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/authlib-1.5.25.jar'
-libraryjars 'tempLibraries/codecjorbis-20101023.jar' -libraryjars 'tempLibraries/codecjorbis-20101023.jar'
@@ -48,22 +48,18 @@
-libraryjars 'tempLibraries/httpclient-4.3.3.jar' -libraryjars 'tempLibraries/httpclient-4.3.3.jar'
-libraryjars 'tempLibraries/httpcore-4.3.2.jar' -libraryjars 'tempLibraries/httpcore-4.3.2.jar'
-libraryjars 'tempLibraries/icu4j-core-mojang-51.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/java-objc-bridge-1.0.0.jar'
-libraryjars 'tempLibraries/jinput-2.0.5.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/jna-4.4.0.jar'
-libraryjars 'tempLibraries/jopt-simple-5.0.3.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/jsr305-3.0.1.jar'
-libraryjars 'tempLibraries/jutils-1.0.0.jar' -libraryjars 'tempLibraries/jutils-1.0.0.jar'
-libraryjars 'tempLibraries/libraryjavasound-20101123.jar' -libraryjars 'tempLibraries/libraryjavasound-20101123.jar'
-libraryjars 'tempLibraries/librarylwjglopenal-20100824.jar' -libraryjars 'tempLibraries/librarylwjglopenal-20100824.jar'
-libraryjars 'tempLibraries/log4j-api-2.8.1.jar' -libraryjars 'tempLibraries/log4j-api-2.8.1.jar'
-libraryjars 'tempLibraries/log4j-core-2.8.1.jar' -libraryjars 'tempLibraries/log4j-core-2.8.1.jar'
-libraryjars 'tempLibraries/lwjgl-2.9.2-nightly-20140822.jar' -libraryjars 'tempLibraries/lwjgl-2.9.4-nightly-20150209.jar'
-libraryjars 'tempLibraries/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar' -libraryjars 'tempLibraries/lwjgl_util-2.9.4-nightly-20150209.jar'
-libraryjars 'tempLibraries/lwjgl_util-2.9.2-nightly-20140822.jar'
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar' -libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
-libraryjars 'tempLibraries/oshi-core-1.1.jar' -libraryjars 'tempLibraries/oshi-core-1.1.jar'
-libraryjars 'tempLibraries/patchy-1.1.jar' -libraryjars 'tempLibraries/patchy-1.1.jar'
@@ -72,8 +68,8 @@
-libraryjars 'tempLibraries/soundsystem-20120107.jar' -libraryjars 'tempLibraries/soundsystem-20120107.jar'
-libraryjars 'tempLibraries/text2speech-1.10.3.jar' -libraryjars 'tempLibraries/text2speech-1.10.3.jar'
-libraryjars 'tempLibraries/mixin-0.7.8-SNAPSHOT.jar' -libraryjars 'tempLibraries/mixin-0.7.11-SNAPSHOT.jar'
-libraryjars 'tempLibraries/launchwrapper-1.12.jar' -libraryjars 'tempLibraries/launchwrapper-1.11.jar' # TODO why does only 1.11.jar exist?
Binary file not shown.
@@ -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 <https://www.gnu.org/licenses/>.
*/
package baritone.api;
import baritone.api.behavior.*;
import baritone.api.cache.IWorldProvider;
/**
* API exposure for various things implemented in Baritone.
* <p>
* 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
}
@@ -15,15 +15,17 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone; package baritone.api;
import baritone.utils.Helper; import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import java.awt.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
@@ -32,6 +34,7 @@ import java.util.function.Consumer;
* @author leijurv * @author leijurv
*/ */
public class Settings { public class Settings {
/** /**
* Allow Baritone to break blocks * Allow Baritone to break blocks
*/ */
@@ -320,8 +323,9 @@ public class Settings {
public Setting<Boolean> prefix = new Setting<>(false); public Setting<Boolean> prefix = new Setting<>(false);
/** /**
* true: can mine blocks when in inventory, chat, or tabbed away in ESC menu * {@code true}: can mine blocks when in inventory, chat, or tabbed away in ESC menu
* false: works on cosmic prisons * <p>
* {@code false}: works on cosmic prisons
* <p> * <p>
* LOL * LOL
*/ */
@@ -389,9 +393,51 @@ public class Settings {
public Setting<Integer> followRadius = new Setting<>(3); public Setting<Integer> 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<Consumer<ITextComponent>> logger = new Setting<>(new Helper() {}::addToChat); public Setting<Consumer<ITextComponent>> logger = new Setting<>(Minecraft.getMinecraft().ingameGUI.getChatGUI()::printChatMessage);
/**
* The color of the current path
*/
public Setting<Color> colorCurrentPath = new Setting<>(Color.RED);
/**
* The color of the next path
*/
public Setting<Color> colorNextPath = new Setting<>(Color.MAGENTA);
/**
* The color of the blocks to break
*/
public Setting<Color> colorBlocksToBreak = new Setting<>(Color.RED);
/**
* The color of the blocks to place
*/
public Setting<Color> colorBlocksToPlace = new Setting<>(Color.GREEN);
/**
* The color of the blocks to walk into
*/
public Setting<Color> colorBlocksToWalkInto = new Setting<>(Color.MAGENTA);
/**
* The color of the best path so far
*/
public Setting<Color> colorBestPathSoFar = new Setting<>(Color.BLUE);
/**
* The color of the path to the most recent considered node
*/
public Setting<Color> colorMostRecentConsidered = new Setting<>(Color.CYAN);
/**
* The color of the goal box
*/
public Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
public final Map<String, Setting<?>> byLowerName; public final Map<String, Setting<?>> byLowerName;
public final List<Setting<?>> allSettings; public final List<Setting<?>> allSettings;
@@ -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 <https://www.gnu.org/licenses/>.
*/
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 {}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Double> 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();
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<ItemStack> getContents();
/**
* @return The number of slots in this inventory
*/
int getSize();
}
@@ -15,9 +15,8 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.utils.pathing; package baritone.api.cache;
import baritone.utils.Helper;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -25,7 +24,7 @@ import net.minecraft.util.math.BlockPos;
* @author Brady * @author Brady
* @since 8/4/2018 2:01 AM * @since 8/4/2018 2:01 AM
*/ */
public interface IBlockTypeAccess extends Helper { public interface IBlockTypeAccess {
IBlockState getBlock(int x, int y, int z); IBlockState getBlock(int x, int y, int z);
+49
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
+82
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<BlockPos> 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();
}
+111
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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> 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);
}
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
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<IWaypoint> 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<IWaypoint> getAllWaypoints();
}
+39
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
+32
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
@@ -15,9 +15,8 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import baritone.pathing.movement.ActionCosts;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
/** /**
@@ -25,22 +24,28 @@ import net.minecraft.util.math.BlockPos;
* *
* @author leijurv * @author leijurv
*/ */
public interface Goal extends ActionCosts { public interface Goal {
/** /**
* Returns whether or not the specified position * Returns whether or not the specified position
* meets the requirement for this goal based. * meets the requirement for this goal based.
* *
* @param pos The position
* @return Whether or not it satisfies this goal * @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 * 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 * @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());
}
} }
@@ -15,28 +15,23 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import baritone.Baritone; import baritone.api.BaritoneAPI;
import net.minecraft.util.math.BlockPos;
public class GoalAxis implements Goal { public class GoalAxis implements Goal {
private static final double SQRT_2_OVER_2 = Math.sqrt(2) / 2; private static final double SQRT_2_OVER_2 = Math.sqrt(2) / 2;
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
int x = pos.getX(); return y == BaritoneAPI.getSettings().axisHeight.get() && (x == 0 || z == 0 || Math.abs(x) == Math.abs(z));
int y = pos.getY();
int z = pos.getZ();
return y == Baritone.settings().axisHeight.get() && (x == 0 || z == 0 || Math.abs(x) == Math.abs(z));
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x0, int y, int z0) {
int x = Math.abs(pos.getX()); int x = Math.abs(x0);
int y = pos.getY(); int z = Math.abs(z0);
int z = Math.abs(pos.getZ());
int shrt = Math.min(x, z); int shrt = Math.min(x, z);
int lng = Math.max(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)); 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 @Override
@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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; import net.minecraft.util.math.BlockPos;
/** /**
@@ -53,15 +53,15 @@ public class GoalBlock implements Goal, IGoalRenderPos {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return pos.getX() == this.x && pos.getY() == this.y && pos.getZ() == this.z; return x == this.x && y == this.y && z == this.z;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
int xDiff = pos.getX() - this.x; int xDiff = x - this.x;
int yDiff = pos.getY() - this.y; int yDiff = y - this.y;
int zDiff = pos.getZ() - this.z; int zDiff = z - this.z;
return calculate(xDiff, yDiff, zDiff); return calculate(xDiff, yDiff, zDiff);
} }
@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -49,15 +49,21 @@ public class GoalComposite implements Goal {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return Arrays.stream(this.goals).anyMatch(goal -> goal.isInGoal(pos)); for (Goal goal : goals) {
if (goal.isInGoal(x, y, z)) {
return true;
}
}
return false;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
double min = Double.MAX_VALUE; double min = Double.MAX_VALUE;
for (Goal g : goals) { 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; return min;
} }
@@ -15,10 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import baritone.utils.interfaces.IGoalRenderPos; import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -41,14 +40,14 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos {
@Override @Override
public BlockPos getGoalPos() { public BlockPos getGoalPos() {
return new BetterBlockPos(x, y, z); return new BlockPos(x, y, z);
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
int xDiff = pos.getX() - this.x; int xDiff = x - this.x;
int yDiff = pos.getY() - this.y; int yDiff = y - this.y;
int zDiff = pos.getZ() - this.z; int zDiff = z - this.z;
if (yDiff < 0) { if (yDiff < 0) {
yDiff++; yDiff++;
} }
@@ -56,10 +55,10 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos {
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
int xDiff = pos.getX() - this.x; int xDiff = x - this.x;
int yDiff = pos.getY() - this.y; int yDiff = y - this.y;
int zDiff = pos.getZ() - this.z; int zDiff = z - this.z;
return GoalBlock.calculate(xDiff, yDiff, zDiff); return GoalBlock.calculate(xDiff, yDiff, zDiff);
} }
@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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; import net.minecraft.util.math.BlockPos;
public class GoalNear implements Goal, IGoalRenderPos { public class GoalNear implements Goal, IGoalRenderPos {
@@ -34,19 +34,19 @@ public class GoalNear implements Goal, IGoalRenderPos {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
int diffX = x - pos.getX(); int xDiff = x - this.x;
int diffY = y - pos.getY(); int yDiff = y - this.y;
int diffZ = z - pos.getZ(); int zDiff = z - this.z;
return diffX * diffX + diffY * diffY + diffZ * diffZ <= rangeSq; return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff <= rangeSq;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
int diffX = x - pos.getX(); int xDiff = x - this.x;
int diffY = y - pos.getY(); int yDiff = y - this.y;
int diffZ = z - pos.getZ(); int zDiff = z - this.z;
return GoalBlock.calculate(diffX, diffY, diffZ); return GoalBlock.calculate(xDiff, yDiff, zDiff);
} }
@Override @Override
@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -41,10 +41,10 @@ public class GoalRunAway implements Goal {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
for (BlockPos p : from) { for (BlockPos p : from) {
int diffX = pos.getX() - p.getX(); int diffX = x - p.getX();
int diffZ = pos.getZ() - p.getZ(); int diffZ = z - p.getZ();
double distSq = diffX * diffX + diffZ * diffZ; double distSq = diffX * diffX + diffZ * diffZ;
if (distSq < distanceSq) { if (distSq < distanceSq) {
return false; return false;
@@ -54,10 +54,10 @@ public class GoalRunAway implements Goal {
} }
@Override @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; double min = Double.MAX_VALUE;
for (BlockPos p : from) { 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) { if (h < min) {
min = h; min = h;
} }
@@ -15,9 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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; import net.minecraft.util.math.BlockPos;
/** /**
@@ -54,18 +54,18 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return pos.getX() == this.x && (pos.getY() == this.y || pos.getY() == this.y - 1) && pos.getZ() == this.z; return x == this.x && (y == this.y || y == this.y - 1) && z == this.z;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
double xDiff = pos.getX() - this.x; int xDiff = x - this.x;
int yDiff = pos.getY() - this.y; int yDiff = y - this.y;
int zDiff = z - this.z;
if (yDiff < 0) { if (yDiff < 0) {
yDiff++; yDiff++;
} }
double zDiff = pos.getZ() - this.z;
return GoalBlock.calculate(xDiff, yDiff, zDiff); return GoalBlock.calculate(xDiff, yDiff, zDiff);
} }
@@ -15,11 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.pathing.goals; package baritone.api.pathing.goals;
import baritone.Baritone; import baritone.api.BaritoneAPI;
import baritone.utils.Utils;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -48,14 +46,14 @@ public class GoalXZ implements Goal {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return pos.getX() == x && pos.getZ() == z; return x == this.x && z == this.z;
} }
@Override @Override
public double heuristic(BlockPos pos) {//mostly copied from GoalBlock public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock
double xDiff = pos.getX() - this.x; int xDiff = x - this.x;
double zDiff = pos.getZ() - this.z; int zDiff = z - this.z;
return calculate(xDiff, zDiff); return calculate(xDiff, zDiff);
} }
@@ -82,11 +80,11 @@ public class GoalXZ implements Goal {
diagonal = z; diagonal = z;
} }
diagonal *= SQRT_2; 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) { 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 x = origin.x - MathHelper.sin(theta) * distance;
double z = origin.z + MathHelper.cos(theta) * distance; double z = origin.z + MathHelper.cos(theta) * distance;
return new GoalXZ((int) x, (int) z); return new GoalXZ((int) x, (int) z);
@@ -15,16 +15,16 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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) * Useful for mining (getting to diamond / iron level)
* *
* @author leijurv * @author leijurv
*/ */
public class GoalYLevel implements Goal { public class GoalYLevel implements Goal, ActionCosts {
/** /**
* The target Y level * The target Y level
@@ -36,13 +36,13 @@ public class GoalYLevel implements Goal {
} }
@Override @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return pos.getY() == level; return y == level;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
return calculate(level, pos.getY()); return calculate(level, y);
} }
public static double calculate(int goalY, int currentY) { public static double calculate(int goalY, int currentY) {
@@ -15,9 +15,36 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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_N_BLOCKS_COST = generateFallNBlocksCost();
double FALL_1_25_BLOCKS_COST = distanceToTicks(1.25); double FALL_1_25_BLOCKS_COST = distanceToTicks(1.25);
@@ -15,13 +15,13 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
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<Float, Float> {
public Rotation(Float yaw, Float pitch) {
super(yaw, pitch);
}
} }
@@ -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 <https://www.gnu.org/licenses/>.
*/
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)
);
}
}
@@ -0,0 +1,54 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.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;
}
}
@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.utils.interfaces; package baritone.api.utils.interfaces;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -23,6 +23,7 @@ import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent; import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.EventState;
import baritone.behavior.PathingBehavior; import baritone.behavior.PathingBehavior;
import baritone.utils.BaritoneAutoTest;
import baritone.utils.ExampleBaritoneControl; import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP; 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.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/** /**
@@ -59,11 +61,22 @@ public class MixinMinecraft {
method = "init", method = "init",
at = @At("RETURN") at = @At("RETURN")
) )
private void init(CallbackInfo ci) { private void postInit(CallbackInfo ci) {
Baritone.INSTANCE.init(); Baritone.INSTANCE.init();
ExampleBaritoneControl.INSTANCE.initAndRegister(); 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( @Inject(
method = "runTick", method = "runTick",
at = @At( at = @At(
+24 -2
View File
@@ -17,10 +17,13 @@
package baritone; package baritone;
import baritone.api.behavior.Behavior; import baritone.api.BaritoneAPI;
import baritone.api.Settings;
import baritone.api.event.listener.IGameEventListener; import baritone.api.event.listener.IGameEventListener;
import baritone.behavior.*; import baritone.behavior.*;
import baritone.cache.WorldProvider;
import baritone.event.GameEventHandler; import baritone.event.GameEventHandler;
import baritone.utils.BaritoneAutoTest;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import net.minecraft.client.Minecraft; 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.threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
this.gameEventHandler = new GameEventHandler(); this.gameEventHandler = new GameEventHandler();
this.inputOverrideHandler = new InputOverrideHandler(); 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<>(); this.behaviors = new ArrayList<>();
{ {
registerBehavior(PathingBehavior.INSTANCE); registerBehavior(PathingBehavior.INSTANCE);
@@ -89,6 +98,19 @@ public enum Baritone {
registerBehavior(LocationTrackingBehavior.INSTANCE); registerBehavior(LocationTrackingBehavior.INSTANCE);
registerBehavior(FollowBehavior.INSTANCE); registerBehavior(FollowBehavior.INSTANCE);
registerBehavior(MineBehavior.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"); this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");
if (!Files.exists(dir.toPath())) { if (!Files.exists(dir.toPath())) {
@@ -15,10 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.api.behavior; package baritone.behavior;
import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.behavior.IBehavior;
import baritone.api.utils.interfaces.Toggleable;
/** /**
* A type of game event listener that can be toggled. * A type of game event listener that can be toggled.
@@ -26,7 +25,7 @@ import baritone.api.utils.interfaces.Toggleable;
* @author Brady * @author Brady
* @since 8/1/2018 6:29 PM * @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 * Whether or not this behavior is enabled
@@ -18,10 +18,10 @@
package baritone.behavior; package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.behavior.Behavior; import baritone.api.behavior.IFollowBehavior;
import baritone.api.event.events.TickEvent; import baritone.api.event.events.TickEvent;
import baritone.pathing.goals.GoalNear; import baritone.api.pathing.goals.GoalNear;
import baritone.pathing.goals.GoalXZ; import baritone.api.pathing.goals.GoalXZ;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -31,7 +31,7 @@ import net.minecraft.util.math.BlockPos;
* *
* @author leijurv * @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(); public static final FollowBehavior INSTANCE = new FollowBehavior();
@@ -42,6 +42,7 @@ public final class FollowBehavior extends Behavior implements Helper {
@Override @Override
public void onTick(TickEvent event) { public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) { if (event.getType() == TickEvent.Type.OUT) {
following = null;
return; return;
} }
if (following == null) { if (following == null) {
@@ -60,14 +61,17 @@ public final class FollowBehavior extends Behavior implements Helper {
PathingBehavior.INSTANCE.path(); PathingBehavior.INSTANCE.path();
} }
@Override
public void follow(Entity entity) { public void follow(Entity entity) {
this.following = entity; this.following = entity;
} }
@Override
public Entity following() { public Entity following() {
return this.following; return this.following;
} }
@Override
public void cancel() { public void cancel() {
PathingBehavior.INSTANCE.cancel(); PathingBehavior.INSTANCE.cancel();
follow(null); follow(null);
@@ -17,10 +17,9 @@
package baritone.behavior; package baritone.behavior;
import baritone.api.behavior.Behavior; import baritone.api.event.events.BlockInteractEvent;
import baritone.cache.Waypoint; import baritone.cache.Waypoint;
import baritone.cache.WorldProvider; import baritone.cache.WorldProvider;
import baritone.api.event.events.BlockInteractEvent;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.block.BlockBed; import net.minecraft.block.BlockBed;
@@ -43,12 +42,12 @@ public final class LocationTrackingBehavior extends Behavior implements Helper {
@Override @Override
public void onBlockInteract(BlockInteractEvent event) { public void onBlockInteract(BlockInteractEvent event) {
if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(event.getPos()) instanceof BlockBed) { 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 @Override
public void onPlayerDeath() { 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()));
} }
} }
@@ -18,14 +18,14 @@
package baritone.behavior; package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.Settings; import baritone.api.Settings;
import baritone.api.behavior.Behavior; import baritone.api.behavior.ILookBehavior;
import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RotationMoveEvent; import baritone.api.event.events.RotationMoveEvent;
import baritone.api.utils.Rotation;
import baritone.utils.Helper; 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(); public static final LookBehavior INSTANCE = new LookBehavior();
@@ -51,6 +51,7 @@ public final class LookBehavior extends Behavior implements Helper {
private LookBehavior() {} private LookBehavior() {}
@Override
public void updateTarget(Rotation target, boolean force) { public void updateTarget(Rotation target, boolean force) {
this.target = target; this.target = target;
this.force = force || !Baritone.settings().freeLook.get(); this.force = force || !Baritone.settings().freeLook.get();
@@ -68,9 +69,9 @@ public final class LookBehavior extends Behavior implements Helper {
switch (event.getState()) { switch (event.getState()) {
case PRE: { case PRE: {
if (this.force) { if (this.force) {
player().rotationYaw = this.target.getFirst(); player().rotationYaw = this.target.getYaw();
float oldPitch = player().rotationPitch; float oldPitch = player().rotationPitch;
float desiredPitch = this.target.getSecond(); float desiredPitch = this.target.getPitch();
player().rotationPitch = desiredPitch; player().rotationPitch = desiredPitch;
if (desiredPitch == oldPitch) { if (desiredPitch == oldPitch) {
nudgeToLevel(); nudgeToLevel();
@@ -78,7 +79,7 @@ public final class LookBehavior extends Behavior implements Helper {
this.target = null; this.target = null;
} else if (silent) { } else if (silent) {
this.lastYaw = player().rotationYaw; this.lastYaw = player().rotationYaw;
player().rotationYaw = this.target.getFirst(); player().rotationYaw = this.target.getYaw();
} }
break; break;
} }
@@ -92,7 +93,6 @@ public final class LookBehavior extends Behavior implements Helper {
default: default:
break; break;
} }
new Thread().start();
} }
@Override @Override
@@ -101,7 +101,7 @@ public final class LookBehavior extends Behavior implements Helper {
switch (event.getState()) { switch (event.getState()) {
case PRE: case PRE:
this.lastYaw = player().rotationYaw; this.lastYaw = player().rotationYaw;
player().rotationYaw = this.target.getFirst(); player().rotationYaw = this.target.getYaw();
break; break;
case POST: case POST:
player().rotationYaw = this.lastYaw; player().rotationYaw = this.lastYaw;
@@ -17,7 +17,11 @@
package baritone.behavior; 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.BlockFire;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
@@ -47,10 +51,10 @@ public final class LookBehaviorUtils implements Helper {
* @return vector of the rotation * @return vector of the rotation
*/ */
public static Vec3d calcVec3dFromRotation(Rotation rotation) { public static Vec3d calcVec3dFromRotation(Rotation rotation) {
float f = MathHelper.cos(-rotation.getFirst() * (float) DEG_TO_RAD - (float) Math.PI); float f = MathHelper.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
float f1 = MathHelper.sin(-rotation.getFirst() * (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.getSecond() * (float) DEG_TO_RAD); float f2 = -MathHelper.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
float f3 = MathHelper.sin(-rotation.getSecond() * (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)); return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
} }
@@ -17,7 +17,8 @@
package baritone.behavior; 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.PacketEvent;
import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.EventState;
@@ -38,7 +39,7 @@ import java.util.*;
* @author Brady * @author Brady
* @since 8/6/2018 9:47 PM * @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(); 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) { public final RememberedInventory getInventoryByPos(BlockPos pos) {
return this.rememberedInventories.get(pos); return this.rememberedInventories.get(pos);
} }
@@ -170,7 +172,7 @@ public final class MemoryBehavior extends Behavior implements Helper {
* <p> * <p>
* Associated with a {@link BlockPos} in {@link MemoryBehavior#rememberedInventories}. * 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 * The list of items in the inventory
@@ -191,11 +193,14 @@ public final class MemoryBehavior extends Behavior implements Helper {
this.items = new ArrayList<>(); this.items = new ArrayList<>();
} }
/** @Override
* @return The list of items in the inventory public final List<ItemStack> getContents() {
*/
public final List<ItemStack> getItems() {
return this.items; return this.items;
} }
@Override
public final int getSize() {
return this.size;
}
} }
} }
@@ -18,17 +18,17 @@
package baritone.behavior; package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.behavior.Behavior; import baritone.api.behavior.IMineBehavior;
import baritone.api.event.events.PathEvent; import baritone.api.event.events.PathEvent;
import baritone.api.event.events.TickEvent; import baritone.api.event.events.TickEvent;
import baritone.api.pathing.goals.Goal;
import baritone.cache.CachedChunk; import baritone.cache.CachedChunk;
import baritone.cache.ChunkPacker; import baritone.cache.ChunkPacker;
import baritone.cache.WorldProvider; import baritone.cache.WorldProvider;
import baritone.cache.WorldScanner; import baritone.cache.WorldScanner;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.GoalBlock;
import baritone.pathing.goals.GoalBlock; import baritone.api.pathing.goals.GoalComposite;
import baritone.pathing.goals.GoalComposite; import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.pathing.goals.GoalTwoBlocks;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@@ -46,7 +46,7 @@ import java.util.stream.Collectors;
* *
* @author leijurv * @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(); public static final MineBehavior INSTANCE = new MineBehavior();
@@ -58,6 +58,10 @@ public final class MineBehavior extends Behavior implements Helper {
@Override @Override
public void onTick(TickEvent event) { public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
cancel();
return;
}
if (mining == null) { if (mining == null) {
return; return;
} }
@@ -74,7 +78,7 @@ public final class MineBehavior extends Behavior implements Helper {
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get();
if (mineGoalUpdateInterval != 0) { if (mineGoalUpdateInterval != 0) {
if (event.getCount() % mineGoalUpdateInterval == 0) { if (event.getCount() % mineGoalUpdateInterval == 0) {
updateGoal(); Baritone.INSTANCE.getExecutor().execute(this::updateGoal);
} }
} }
PathingBehavior.INSTANCE.revalidateGoal(); PathingBehavior.INSTANCE.revalidateGoal();
@@ -105,7 +109,7 @@ public final class MineBehavior extends Behavior implements Helper {
PathingBehavior.INSTANCE.path(); PathingBehavior.INSTANCE.path();
} }
public static GoalComposite coalesce(List<BlockPos> locs) { public GoalComposite coalesce(List<BlockPos> locs) {
return new GoalComposite(locs.stream().map(loc -> { return new GoalComposite(locs.stream().map(loc -> {
if (!Baritone.settings().forceInternalMining.get()) { if (!Baritone.settings().forceInternalMining.get()) {
return new GoalTwoBlocks(loc); return new GoalTwoBlocks(loc);
@@ -129,13 +133,13 @@ public final class MineBehavior extends Behavior implements Helper {
}).toArray(Goal[]::new)); }).toArray(Goal[]::new));
} }
public static List<BlockPos> scanFor(List<Block> mining, int max) { public List<BlockPos> scanFor(List<Block> mining, int max) {
List<BlockPos> locs = new ArrayList<>(); List<BlockPos> locs = new ArrayList<>();
List<Block> uninteresting = new ArrayList<>(); List<Block> uninteresting = new ArrayList<>();
//long b = System.currentTimeMillis(); //long b = System.currentTimeMillis();
for (Block m : mining) { for (Block m : mining) {
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(m)) { 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 { } else {
uninteresting.add(m); uninteresting.add(m);
} }
@@ -152,7 +156,7 @@ public final class MineBehavior extends Behavior implements Helper {
return prune(locs, mining, max); return prune(locs, mining, max);
} }
public static List<BlockPos> prune(List<BlockPos> locs, List<Block> mining, int max) { public List<BlockPos> prune(List<BlockPos> locs, List<Block> mining, int max) {
BlockPos playerFeet = MineBehavior.INSTANCE.playerFeet(); BlockPos playerFeet = MineBehavior.INSTANCE.playerFeet();
locs.sort(Comparator.comparingDouble(playerFeet::distanceSq)); locs.sort(Comparator.comparingDouble(playerFeet::distanceSq));
@@ -167,6 +171,7 @@ public final class MineBehavior extends Behavior implements Helper {
return locs; return locs;
} }
@Override
public void mine(int quantity, String... blocks) { 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.mining = blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(ChunkPacker::stringToBlock).collect(Collectors.toList());
this.quantity = quantity; this.quantity = quantity;
@@ -174,12 +179,15 @@ public final class MineBehavior extends Behavior implements Helper {
updateGoal(); 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.mining = blocks == null || blocks.length == 0 ? null : Arrays.asList(blocks);
this.quantity = quantity;
this.locationsCache = new ArrayList<>(); this.locationsCache = new ArrayList<>();
updateGoal(); updateGoal();
} }
@Override
public void cancel() { public void cancel() {
mine(0, (String[]) null); mine(0, (String[]) null);
PathingBehavior.INSTANCE.cancel(); PathingBehavior.INSTANCE.cancel();
@@ -18,33 +18,36 @@
package baritone.behavior; package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.behavior.Behavior; import baritone.api.behavior.IPathingBehavior;
import baritone.api.event.events.PathEvent; import baritone.api.event.events.PathEvent;
import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RenderEvent; import baritone.api.event.events.RenderEvent;
import baritone.api.event.events.TickEvent; 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.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.calc.IPathFinder; import baritone.pathing.calc.IPathFinder;
import baritone.pathing.goals.Goal;
import baritone.pathing.goals.GoalXZ;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import baritone.pathing.path.PathExecutor; import baritone.pathing.path.PathExecutor;
import baritone.utils.BlockBreakHelper;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.PathRenderer; import baritone.utils.PathRenderer;
import baritone.utils.interfaces.IGoalRenderPos;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk; import net.minecraft.world.chunk.EmptyChunk;
import java.awt.*; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.Optional; 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(); public static final PathingBehavior INSTANCE = new PathingBehavior();
@@ -170,6 +173,7 @@ public final class PathingBehavior extends Behavior implements Helper {
} }
} }
@Override
public Optional<Double> ticksRemainingInSegment() { public Optional<Double> ticksRemainingInSegment() {
if (current == null) { if (current == null) {
return Optional.empty(); return Optional.empty();
@@ -177,10 +181,12 @@ public final class PathingBehavior extends Behavior implements Helper {
return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition())); return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition()));
} }
@Override
public void setGoal(Goal goal) { public void setGoal(Goal goal) {
this.goal = goal; this.goal = goal;
} }
@Override
public Goal getGoal() { public Goal getGoal() {
return goal; return goal;
} }
@@ -193,16 +199,30 @@ public final class PathingBehavior extends Behavior implements Helper {
return next; 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<IPath> getPath() { public Optional<IPath> getPath() {
return Optional.ofNullable(current).map(PathExecutor::getPath); return Optional.ofNullable(current).map(PathExecutor::getPath);
} }
@Override
public boolean isPathing() {
return this.current != null;
}
@Override
public void cancel() { public void cancel() {
dispatchPathEvent(PathEvent.CANCELED); dispatchPathEvent(PathEvent.CANCELED);
current = null; current = null;
next = null; next = null;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(AbstractNodeCostSearch::cancel); 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 * @return true if this call started path calculation, false if it was already calculating or executing a path
*/ */
@Override
public boolean path() { public boolean path() {
if (goal == null) { if (goal == null) {
return false; 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(); BetterBlockPos feet = playerFeet();
if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR) && MovementHelper.canWalkOn(feet.down().down())) { if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR) && MovementHelper.canWalkOn(feet.down().down())) {
return feet.down(); return feet.down();
@@ -246,7 +270,8 @@ public final class PathingBehavior extends Behavior implements Helper {
* @param start * @param start
* @param talkAboutIt * @param talkAboutIt
*/ */
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, final Optional<IPath> previous) { private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt,
final Optional<IPath> previous) {
synchronized (pathCalcLock) { synchronized (pathCalcLock) {
if (isPathCalcInProgress) { if (isPathCalcInProgress) {
throw new IllegalStateException("Already doing it"); throw new IllegalStateException("Already doing it");
@@ -329,8 +354,9 @@ public final class PathingBehavior extends Behavior implements Helper {
} else { } else {
timeout = Baritone.settings().planAheadTimeoutMS.<Long>get(); timeout = Baritone.settings().planAheadTimeoutMS.<Long>get();
} }
Optional<HashSet<Long>> 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 { try {
IPathFinder pf = new AStarPathFinder(start, goal, previous.map(IPath::positions)); IPathFinder pf = new AStarPathFinder(start, goal, favoredPositions);
return pf.calculate(timeout); return pf.calculate(timeout);
} catch (Exception e) { } catch (Exception e) {
logDebug("Pathing exception: " + e); logDebug("Pathing exception: " + e);
@@ -361,7 +387,7 @@ public final class PathingBehavior extends Behavior implements Helper {
// System.out.println(event.getPartialTicks()); // System.out.println(event.getPartialTicks());
float partialTicks = event.getPartialTicks(); float partialTicks = event.getPartialTicks();
if (goal != null && Baritone.settings().renderGoal.value) { 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()) { if (!Baritone.settings().renderPath.get()) {
return; return;
@@ -378,27 +404,27 @@ public final class PathingBehavior extends Behavior implements Helper {
// Render the current path, if there is one // Render the current path, if there is one
if (current != null && current.getPath() != null) { if (current != null && current.getPath() != null) {
int renderBegin = Math.max(current.getPosition() - 3, 0); 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) { 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(); //long split = System.nanoTime();
if (current != null) { if (current != null) {
PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Color.RED); PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get());
PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Color.GREEN); PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get());
PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Color.MAGENTA); PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get());
} }
// If there is a path calculation currently running, render the path calculation process // If there is a path calculation currently running, render the path calculation process
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> { AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
currentlyRunning.bestPathSoFar().ifPresent(p -> { 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 -> { currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
PathRenderer.drawPath(mr, 0, player(), partialTicks, Color.CYAN, Baritone.settings().fadePath.get(), 10, 20); PathRenderer.drawPath(mr, 0, player(), partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20);
PathRenderer.drawManySelectionBoxes(player(), Collections.singletonList(mr.getDest()), partialTicks, Color.CYAN); 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)); // System.out.println("Frame took " + (split - start) + " " + (end - split));
//} //}
} }
@Override
public void onDisable() {
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
} }
+7 -7
View File
@@ -17,7 +17,8 @@
package baritone.cache; package baritone.cache;
import baritone.utils.pathing.IBlockTypeAccess; import baritone.api.cache.IBlockTypeAccess;
import baritone.utils.Helper;
import baritone.utils.pathing.PathingBlockType; import baritone.utils.pathing.PathingBlockType;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
@@ -30,7 +31,7 @@ import java.util.*;
* @author Brady * @author Brady
* @since 8/3/2018 1:04 AM * @since 8/3/2018 1:04 AM
*/ */
public final class CachedChunk implements IBlockTypeAccess { public final class CachedChunk implements IBlockTypeAccess, Helper {
public static final Set<Block> BLOCKS_TO_KEEP_TRACK_OF = Collections.unmodifiableSet(new HashSet<Block>() {{ public static final Set<Block> BLOCKS_TO_KEEP_TRACK_OF = Collections.unmodifiableSet(new HashSet<Block>() {{
add(Blocks.DIAMOND_ORE); 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 * 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 int[] heightMap;
private final Map<String, List<BlockPos>> specialBlockLocations; private final Map<String, List<BlockPos>> specialBlockLocations;
CachedChunk(int x, int z, BitSet data, String[] overview, Map<String, List<BlockPos>> specialBlockLocations) { CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map<String, List<BlockPos>> specialBlockLocations) {
validateSize(data); validateSize(data);
this.x = x; this.x = x;
@@ -122,12 +123,11 @@ public final class CachedChunk implements IBlockTypeAccess {
int internalPos = z << 4 | x; int internalPos = z << 4 | x;
if (heightMap[internalPos] == y) { if (heightMap[internalPos] == y) {
// we have this exact block, it's a surface block // 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); /*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())) { 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)); 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); PathingBlockType type = getType(x, y, z);
if (type == PathingBlockType.SOLID && y == 127 && mc.player.dimension == -1) { 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; return overview;
} }
+9 -5
View File
@@ -17,7 +17,7 @@
package baritone.cache; package baritone.cache;
import baritone.utils.pathing.IBlockTypeAccess; import baritone.api.cache.ICachedRegion;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -33,7 +33,8 @@ import java.util.zip.GZIPOutputStream;
* @author Brady * @author Brady
* @since 8/3/2018 9:35 PM * @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_NOT_PRESENT = 0;
private static final byte CHUNK_PRESENT = 1; private static final byte CHUNK_PRESENT = 1;
@@ -77,6 +78,7 @@ public final class CachedRegion implements IBlockTypeAccess {
return null; return null;
} }
@Override
public final boolean isCached(int x, int z) { public final boolean isCached(int x, int z) {
return chunks[x >> 4][z >> 4] != null; return chunks[x >> 4][z >> 4] != null;
} }
@@ -145,7 +147,7 @@ public final class CachedRegion implements IBlockTypeAccess {
for (int x = 0; x < 32; x++) { for (int x = 0; x < 32; x++) {
if (chunks[x][z] != null) { if (chunks[x][z] != null) {
for (int i = 0; i < 256; i++) { 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 regionZ = this.z;
int chunkX = x + 32 * regionX; int chunkX = x + 32 * regionX;
int chunkZ = z + 32 * regionZ; 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; break;
case CHUNK_NOT_PRESENT: case CHUNK_NOT_PRESENT:
tmpCached[x][z] = null; tmpCached[x][z] = null;
@@ -229,7 +231,7 @@ public final class CachedRegion implements IBlockTypeAccess {
for (int x = 0; x < 32; x++) { for (int x = 0; x < 32; x++) {
if (tmpCached[x][z] != null) { if (tmpCached[x][z] != null) {
for (int i = 0; i < 256; i++) { 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 * @return The region x coordinate
*/ */
@Override
public final int getX() { public final int getX() {
return this.x; return this.x;
} }
@@ -287,6 +290,7 @@ public final class CachedRegion implements IBlockTypeAccess {
/** /**
* @return The region z coordinate * @return The region z coordinate
*/ */
@Override
public final int getZ() { public final int getZ() {
return this.z; return this.z;
} }
+16 -18
View File
@@ -18,6 +18,7 @@
package baritone.cache; package baritone.cache;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.cache.ICachedWorld;
import baritone.utils.Helper; import baritone.utils.Helper;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@@ -36,7 +37,7 @@ import java.util.concurrent.LinkedBlockingQueue;
* @author Brady * @author Brady
* @since 8/4/2018 12:02 AM * @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) * 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) { public final void queueForPacking(Chunk chunk) {
try { try {
toPack.put(chunk); toPack.put(chunk);
@@ -91,17 +93,17 @@ public final class CachedWorld implements Helper {
} }
} }
public final boolean isCached(BlockPos pos) { @Override
int x = pos.getX(); public final boolean isCached(int blockX, int blockZ) {
int z = pos.getZ(); CachedRegion region = getRegion(blockX >> 9, blockZ >> 9);
CachedRegion region = getRegion(x >> 9, z >> 9);
if (region == null) { if (region == null) {
return false; return false;
} }
return region.isCached(x & 511, z & 511); return region.isCached(blockX & 511, blockZ & 511);
} }
public final LinkedList<BlockPos> getLocationsOf(String block, int minimum, int maxRegionDistanceSq) { @Override
public final LinkedList<BlockPos> getLocationsOf(String block, int maximum, int maxRegionDistanceSq) {
LinkedList<BlockPos> res = new LinkedList<>(); LinkedList<BlockPos> res = new LinkedList<>();
int playerRegionX = playerFeet().getX() >> 9; int playerRegionX = playerFeet().getX() >> 9;
int playerRegionZ = playerFeet().getZ() >> 9; int playerRegionZ = playerFeet().getZ() >> 9;
@@ -118,13 +120,12 @@ public final class CachedWorld implements Helper {
int regionZ = zoff + playerRegionZ; int regionZ = zoff + playerRegionZ;
CachedRegion region = getOrCreateRegion(regionX, regionZ); CachedRegion region = getOrCreateRegion(regionX, regionZ);
if (region != null) { if (region != null) {
for (BlockPos pos : region.getLocationsOf(block)) { // TODO: 100% verify if this or addAll is faster.
res.add(pos); region.getLocationsOf(block).forEach(res::add);
}
} }
} }
} }
if (res.size() >= minimum) { if (res.size() >= maximum) {
return res; return res;
} }
searchRadius++; searchRadius++;
@@ -137,6 +138,7 @@ public final class CachedWorld implements Helper {
region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk); region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk);
} }
@Override
public final void save() { public final void save() {
if (!Baritone.settings().chunkCaching.get()) { if (!Baritone.settings().chunkCaching.get()) {
System.out.println("Not saving to disk; chunk caching is disabled."); 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()); return new ArrayList<>(this.cachedRegions.values());
} }
@Override
public final void reloadAllFromDisk() { public final void reloadAllFromDisk() {
long start = System.nanoTime() / 1000000L; long start = System.nanoTime() / 1000000L;
allRegions().forEach(region -> { allRegions().forEach(region -> {
@@ -167,13 +170,7 @@ public final class CachedWorld implements Helper {
System.out.println("World load took " + (now - start) + "ms"); System.out.println("World load took " + (now - start) + "ms");
} }
/** @Override
* 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
*/
public final synchronized CachedRegion getRegion(int regionX, int regionZ) { public final synchronized CachedRegion getRegion(int regionX, int regionZ) {
return cachedRegions.get(getRegionID(regionX, regionZ)); return cachedRegions.get(getRegionID(regionX, regionZ));
} }
@@ -224,6 +221,7 @@ public final class CachedWorld implements Helper {
private class PackerThread implements Runnable { private class PackerThread implements Runnable {
public void run() { public void run() {
while (true) { while (true) {
// TODO: Add CachedWorld unloading to remove the redundancy of having this
LinkedBlockingQueue<Chunk> queue = toPack; LinkedBlockingQueue<Chunk> queue = toPack;
if (queue == null) { if (queue == null) {
break; break;
+7 -5
View File
@@ -89,22 +89,24 @@ public final class ChunkPacker implements Helper {
} }
//long end = System.nanoTime() / 1000000L; //long end = System.nanoTime() / 1000000L;
//System.out.println("Chunk packing took " + (end - start) + "ms for " + chunk.x + "," + chunk.z); //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++) { for (int z = 0; z < 16; z++) {
// @formatter:off
https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html 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 x = 0; x < 16; x++) {
for (int y = 255; y >= 0; y--) { for (int y = 255; y >= 0; y--) {
int index = CachedChunk.getPositionIndex(x, y, z); int index = CachedChunk.getPositionIndex(x, y, z);
if (bitSet.get(index) || bitSet.get(index + 1)) { if (bitSet.get(index) || bitSet.get(index + 1)) {
String name = blockToString(chunk.getBlockState(x, y, z).getBlock()); blocks[z << 4 | x] = chunk.getBlockState(x, y, z);
blockNames[z << 4 | x] = name;
continue https; 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) { public static String blockToString(Block block) {
+43 -38
View File
@@ -17,77 +17,82 @@
package baritone.cache; package baritone.cache;
import com.google.common.collect.ImmutableList; import baritone.api.cache.IWaypoint;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.apache.commons.lang3.ArrayUtils;
import java.util.Date; import java.util.Date;
import java.util.List;
/** /**
* A single waypoint * Basic implementation of {@link IWaypoint}
* *
* @author leijurv * @author leijurv
*/ */
public class Waypoint { public class Waypoint implements IWaypoint {
public final String name; private final String name;
public final Tag tag; private final Tag tag;
private final long creationTimestamp; private final long creationTimestamp;
public final BlockPos location; private final BlockPos location;
public Waypoint(String name, Tag tag, BlockPos location) { public Waypoint(String name, Tag tag, BlockPos location) {
this(name, tag, location, System.currentTimeMillis()); 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.name = name;
this.tag = tag; this.tag = tag;
this.location = location; this.location = location;
this.creationTimestamp = creationTimestamp; 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 @Override
public int hashCode() { public int hashCode() {
return name.hashCode() + tag.hashCode() + location.hashCode(); //lol return name.hashCode() + tag.hashCode() + location.hashCode(); //lol
} }
public long creationTimestamp() { @Override
return creationTimestamp; 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() { public String toString() {
return name + " " + location.toString() + " " + new Date(creationTimestamp).toString(); return name + " " + location.toString() + " " + new Date(creationTimestamp).toString();
} }
public enum Tag { @Override
HOME("home", "base"), public boolean equals(Object o) {
DEATH("death"), if (o == null) {
BED("bed", "spawn"), return false;
USER("user");
private static final List<Tag> TAG_LIST = ImmutableList.<Tag>builder().add(Tag.values()).build();
private final String[] names;
Tag(String... names) {
this.names = names;
} }
if (!(o instanceof IWaypoint)) {
public static Tag fromString(String name) { return false;
return TAG_LIST.stream().filter(tag -> ArrayUtils.contains(tag.names, name.toLowerCase())).findFirst().orElse(null);
} }
IWaypoint w = (IWaypoint) o;
return name.equals(w.getName()) && tag == w.getTag() && location.equals(w.getLocation());
} }
} }
+44 -25
View File
@@ -17,19 +17,22 @@
package baritone.cache; package baritone.cache;
import baritone.api.cache.IWaypoint;
import baritone.api.cache.IWaypointCollection;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.io.*; import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* Waypoints for a world * Waypoints for a world
* *
* @author leijurv * @author leijurv
*/ */
public class Waypoints { public class Waypoints implements IWaypointCollection {
/** /**
* Magic value to detect invalid waypoint files * 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 static final long WAYPOINT_MAGIC_VALUE = 121977993584L; // good value
private final Path directory; private final Path directory;
private final Map<Waypoint.Tag, Set<Waypoint>> waypoints; private final Map<IWaypoint.Tag, Set<IWaypoint>> waypoints;
Waypoints(Path directory) { Waypoints(Path directory) {
this.directory = directory; this.directory = directory;
@@ -58,9 +61,9 @@ public class Waypoints {
} }
private synchronized void load(Waypoint.Tag tag) { 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)) { if (!Files.exists(fileName)) {
return; return;
} }
@@ -82,44 +85,60 @@ public class Waypoints {
int x = in.readInt(); int x = in.readInt();
int y = in.readInt(); int y = in.readInt();
int z = 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) {} } catch (IOException ignored) {}
} }
private synchronized void save(Waypoint.Tag tag) { 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 ( try (
FileOutputStream fileOut = new FileOutputStream(fileName.toFile()); FileOutputStream fileOut = new FileOutputStream(fileName.toFile());
BufferedOutputStream bufOut = new BufferedOutputStream(fileOut); BufferedOutputStream bufOut = new BufferedOutputStream(fileOut);
DataOutputStream out = new DataOutputStream(bufOut) DataOutputStream out = new DataOutputStream(bufOut)
) { ) {
out.writeLong(WAYPOINT_MAGIC_VALUE); out.writeLong(WAYPOINT_MAGIC_VALUE);
out.writeLong(waypoints.get(tag).size()); out.writeLong(this.waypoints.get(tag).size());
for (Waypoint waypoint : waypoints.get(tag)) { for (IWaypoint waypoint : this.waypoints.get(tag)) {
out.writeUTF(waypoint.name); out.writeUTF(waypoint.getName());
out.writeLong(waypoint.creationTimestamp()); out.writeLong(waypoint.getCreationTimestamp());
out.writeInt(waypoint.location.getX()); out.writeInt(waypoint.getLocation().getX());
out.writeInt(waypoint.location.getY()); out.writeInt(waypoint.getLocation().getY());
out.writeInt(waypoint.location.getZ()); out.writeInt(waypoint.getLocation().getZ());
} }
} catch (IOException ex) { } catch (IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
public Set<Waypoint> getByTag(Waypoint.Tag tag) { @Override
return Collections.unmodifiableSet(waypoints.get(tag)); public void addWaypoint(IWaypoint waypoint) {
}
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) {
// no need to check for duplicate, because it's a Set not a List // no need to check for duplicate, because it's a Set not a List
waypoints.get(waypoint.tag).add(waypoint); if (waypoints.get(waypoint.getTag()).add(waypoint)) {
save(waypoint.tag); 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<IWaypoint> getByTag(IWaypoint.Tag tag) {
return Collections.unmodifiableSet(this.waypoints.get(tag));
}
@Override
public Set<IWaypoint> getAllWaypoints() {
return this.waypoints.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
} }
} }
+16 -2
View File
@@ -18,6 +18,9 @@
package baritone.cache; package baritone.cache;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.cache.ICachedWorld;
import baritone.api.cache.IWaypointCollection;
import baritone.api.cache.IWorldData;
import java.nio.file.Path; import java.nio.file.Path;
@@ -26,9 +29,10 @@ import java.nio.file.Path;
* *
* @author leijurv * @author leijurv
*/ */
public class WorldData { public class WorldData implements IWorldData {
public final CachedWorld cache; public final CachedWorld cache;
public final Waypoints waypoints; private final Waypoints waypoints;
//public final MapData map; //public final MapData map;
public final Path directory; public final Path directory;
@@ -44,4 +48,14 @@ public class WorldData {
cache.save(); cache.save();
}); });
} }
@Override
public ICachedWorld getCachedWorld() {
return this.cache;
}
@Override
public IWaypointCollection getWaypoints() {
return this.waypoints;
}
} }
+3 -1
View File
@@ -18,6 +18,7 @@
package baritone.cache; package baritone.cache;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.cache.IWorldProvider;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.accessor.IAnvilChunkLoader; import baritone.utils.accessor.IAnvilChunkLoader;
import baritone.utils.accessor.IChunkProviderServer; import baritone.utils.accessor.IChunkProviderServer;
@@ -38,7 +39,7 @@ import java.util.function.Consumer;
* @author Brady * @author Brady
* @since 8/4/2018 11:06 AM * @since 8/4/2018 11:06 AM
*/ */
public enum WorldProvider implements Helper { public enum WorldProvider implements IWorldProvider, Helper {
INSTANCE; INSTANCE;
@@ -46,6 +47,7 @@ public enum WorldProvider implements Helper {
private WorldData currentWorld; private WorldData currentWorld;
@Override
public final WorldData getCurrentWorld() { public final WorldData getCurrentWorld() {
return this.currentWorld; return this.currentWorld;
} }
@@ -109,7 +109,7 @@ public final class GameEventHandler implements IGameEventListener, Helper {
if (isPostPopulate || isPreUnload) { if (isPostPopulate || isPreUnload) {
WorldProvider.INSTANCE.ifWorldLoaded(world -> { WorldProvider.INSTANCE.ifWorldLoaded(world -> {
Chunk chunk = mc.world.getChunk(event.getX(), event.getZ()); Chunk chunk = mc.world.getChunk(event.getX(), event.getZ());
world.cache.queueForPacking(chunk); world.getCachedWorld().queueForPacking(chunk);
}); });
} }
@@ -18,22 +18,16 @@
package baritone.pathing.calc; package baritone.pathing.calc;
import baritone.Baritone; import baritone.Baritone;
import baritone.cache.CachedWorld; import baritone.api.pathing.goals.Goal;
import baritone.cache.WorldProvider; import baritone.api.pathing.movement.ActionCosts;
import baritone.pathing.calc.openset.BinaryHeapOpenSet; 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.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.movements.*;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft; import baritone.utils.pathing.MoveResult;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.*; import java.util.*;
@@ -43,20 +37,18 @@ import java.util.*;
* *
* @author leijurv * @author leijurv
*/ */
public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
private final Optional<HashSet<BetterBlockPos>> favoredPositions; private final Optional<HashSet<Long>> favoredPositions;
private final Random random = new Random(); public AStarPathFinder(BlockPos start, Goal goal, Optional<HashSet<Long>> favoredPositions) {
public AStarPathFinder(BlockPos start, Goal goal, Optional<Collection<BetterBlockPos>> favoredPositions) {
super(start, goal); super(start, goal);
this.favoredPositions = favoredPositions.map(HashSet::new); // <-- okay this is epic this.favoredPositions = favoredPositions;
} }
@Override @Override
protected Optional<IPath> calculate0(long timeout) { protected Optional<IPath> calculate0(long timeout) {
startNode = getNodeAtPosition(start); startNode = getNodeAtPosition(start.x, start.y, start.z);
startNode.cost = 0; startNode.cost = 0;
startNode.combinedCost = startNode.estimatedCostToGoal; startNode.combinedCost = startNode.estimatedCostToGoal;
BinaryHeapOpenSet openSet = new BinaryHeapOpenSet(); BinaryHeapOpenSet openSet = new BinaryHeapOpenSet();
@@ -69,9 +61,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
bestSoFar[i] = startNode; bestSoFar[i] = startNode;
} }
CalculationContext calcContext = new CalculationContext(); CalculationContext calcContext = new CalculationContext();
HashSet<BetterBlockPos> favored = favoredPositions.orElse(null); HashSet<Long> favored = favoredPositions.orElse(null);
CachedWorld cachedWorld = Optional.ofNullable(WorldProvider.INSTANCE.getCurrentWorld()).map(w -> w.cache).orElse(null);
ChunkProviderClient chunkProvider = Minecraft.getMinecraft().world.getChunkProvider();
BlockStateInterface.clearCachedChunk(); BlockStateInterface.clearCachedChunk();
long startTime = System.nanoTime() / 1000000L; long startTime = System.nanoTime() / 1000000L;
boolean slowPath = Baritone.settings().slowPath.get(); boolean slowPath = Baritone.settings().slowPath.get();
@@ -88,10 +78,10 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get(); boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get();
HashMap<Class<? extends Movement>, Long> timeConsumed = new HashMap<>(); long[] timeConsumed = new long[Moves.values().length];
HashMap<Class<? extends Movement>, Integer> count = new HashMap<>(); int[] count = new int[Moves.values().length];
HashMap<Class<? extends Movement>, Integer> stateLookup = new HashMap<>(); int[] stateLookup = new int[Moves.values().length];
HashMap<Class<? extends Movement>, Long> posCreation = new HashMap<>(); long[] posCreation = new long[Moves.values().length];
long heapRemove = 0; long heapRemove = 0;
int heapRemoveCount = 0; int heapRemoveCount = 0;
long heapAdd = 0; long heapAdd = 0;
@@ -99,9 +89,6 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
long heapUpdate = 0; long heapUpdate = 0;
int heapUpdateCount = 0; int heapUpdateCount = 0;
long construction = 0;
int constructionCount = 0;
long chunk = 0; long chunk = 0;
int chunkCount = 0; int chunkCount = 0;
@@ -129,36 +116,24 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
heapRemoveCount++; heapRemoveCount++;
currentNode.isOpen = false; currentNode.isOpen = false;
mostRecentConsidered = currentNode; mostRecentConsidered = currentNode;
BetterBlockPos currentNodePos = currentNode.pos;
numNodes++; numNodes++;
if (goal.isInGoal(currentNodePos)) { if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) {
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered"); logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
return Optional.of(new Path(startNode, currentNode, numNodes, goal)); return Optional.of(new Path(startNode, currentNode, numNodes, goal));
} }
long constructStart = System.nanoTime(); goalCheck += System.nanoTime() - t;
goalCheck += constructStart - t;
goalCheckCount++; goalCheckCount++;
Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos, in random order for (Moves moves : Moves.values()) {
shuffle(possibleMovements);
long constructEnd = System.nanoTime();
construction += constructEnd - constructStart;
constructionCount++;
for (Movement movementToGetToNeighbor : possibleMovements) {
if (movementToGetToNeighbor == null) {
continue;
}
BetterBlockPos dest = movementToGetToNeighbor.getDest();
long s = System.nanoTime(); long s = System.nanoTime();
int chunkX = currentNodePos.x >> 4; int newX = currentNode.x + moves.xOffset;
int chunkZ = currentNodePos.z >> 4; int newZ = currentNode.z + moves.zOffset;
if (dest.x >> 4 != chunkX || dest.z >> 4 != chunkZ) { 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 // 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)) { if (!BlockStateInterface.isLoaded(newX, newZ)) {
// see issue #106 if (!moves.dynamicXZ) { // only increment the counter if the movement would have gone out of bounds guaranteed
if (cachedWorld == null || !cachedWorld.isCached(dest)) {
numEmptyChunk++; numEmptyChunk++;
continue;
} }
continue;
} }
} }
long costStart = System.nanoTime(); long costStart = System.nanoTime();
@@ -167,31 +142,39 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
// TODO cache cost // TODO cache cost
int numLookupsBefore = BlockStateInterface.numBlockStateLookups; int numLookupsBefore = BlockStateInterface.numBlockStateLookups;
long numCreatedBefore = BetterBlockPos.numCreated; long numCreatedBefore = BetterBlockPos.numCreated;
double actionCost = movementToGetToNeighbor.getCost(calcContext);
MoveResult res = moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z);
long costEnd = System.nanoTime(); long costEnd = System.nanoTime();
stateLookup.put(movementToGetToNeighbor.getClass(), BlockStateInterface.numBlockStateLookups - numLookupsBefore + stateLookup.getOrDefault(movementToGetToNeighbor.getClass(), 0)); stateLookup[moves.ordinal()] += BlockStateInterface.numBlockStateLookups - numLookupsBefore;
posCreation.put(movementToGetToNeighbor.getClass(), BetterBlockPos.numCreated - numCreatedBefore + posCreation.getOrDefault(movementToGetToNeighbor.getClass(), 0L)); posCreation[moves.ordinal()] += BetterBlockPos.numCreated - numCreatedBefore;
timeConsumed.put(movementToGetToNeighbor.getClass(), costEnd - costStart + timeConsumed.getOrDefault(movementToGetToNeighbor.getClass(), 0L)); timeConsumed[moves.ordinal()] += costEnd - costStart;
count.put(movementToGetToNeighbor.getClass(), 1 + count.getOrDefault(movementToGetToNeighbor.getClass(), 0)); count[moves.ordinal()]++;
numMovementsConsidered++; numMovementsConsidered++;
double actionCost = res.cost;
if (actionCost >= ActionCosts.COST_INF) { if (actionCost >= ActionCosts.COST_INF) {
continue; continue;
} }
if (actionCost <= 0) { // 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
throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost); 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 // see issue #18
actionCost *= favorCoeff; actionCost *= favorCoeff;
} }
long st = System.nanoTime(); long st = System.nanoTime();
PathNode neighbor = getNodeAtPosition(dest); PathNode neighbor = getNodeAtPosition(res.destX, res.destY, res.destZ);
getNode += System.nanoTime() - st; getNode += System.nanoTime() - st;
getNodeCount++; getNodeCount++;
double tentativeCost = currentNode.cost + actionCost; double tentativeCost = currentNode.cost + actionCost;
if (tentativeCost < neighbor.cost) { if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) { 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; double improvementBy = neighbor.cost - tentativeCost;
// there are floating point errors caused by random combinations of traverse and diagonal over a flat area // 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; continue;
} }
neighbor.previous = currentNode; neighbor.previous = currentNode;
neighbor.previousMovement = movementToGetToNeighbor;
neighbor.cost = tentativeCost; neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal; neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen) { if (neighbor.isOpen) {
@@ -235,21 +217,20 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
long numSuccc = BetterBlockPos.numCreated - startVal3; 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("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("Instantiated " + numSuccc + " BetterBlockPos objects");
System.out.println("Remove " + (heapRemove / heapRemoveCount) + " " + heapRemove / 1000000 + " " + heapRemoveCount); System.out.println("Remove " + (heapRemove / heapRemoveCount) + " " + heapRemove / 1000000 + "ms " + heapRemoveCount);
System.out.println("Add " + (heapAdd / heapAddCount) + " " + heapAdd / 1000000 + " " + heapAddCount); System.out.println("Add " + (heapAdd / heapAddCount) + " " + heapAdd / 1000000 + "ms " + heapAddCount);
System.out.println("Update " + (heapUpdate / heapUpdateCount) + " " + heapUpdate / 1000000 + " " + heapUpdateCount); System.out.println("Update " + (heapUpdate / heapUpdateCount) + " " + heapUpdate / 1000000 + "ms " + heapUpdateCount);
System.out.println("Construction " + (construction / constructionCount) + " " + construction / 1000000 + " " + constructionCount); System.out.println("Chunk " + (chunk / chunkCount) + " " + chunk / 1000000 + "ms " + chunkCount);
System.out.println("Chunk " + (chunk / chunkCount) + " " + chunk / 1000000 + " " + chunkCount); System.out.println("GetNode " + (getNode / getNodeCount) + " " + getNode / 1000000 + "ms " + getNodeCount);
System.out.println("GetNode " + (getNode / getNodeCount) + " " + getNode / 1000000 + " " + getNodeCount); System.out.println("GoalCheck " + (goalCheck / goalCheckCount) + " " + goalCheck / 1000000 + "ms " + goalCheckCount);
System.out.println("GoalCheck " + (goalCheck / goalCheckCount) + " " + goalCheck / 1000000 + " " + goalCheckCount); ArrayList<Moves> moves = new ArrayList<>(Arrays.asList(Moves.values()));
ArrayList<Class<? extends Movement>> klasses = new ArrayList<>(count.keySet()); moves.sort(Comparator.comparingLong(k -> timeConsumed[k.ordinal()] / count[k.ordinal()]));
klasses.sort(Comparator.comparingLong(k -> timeConsumed.get(k) / count.get(k))); for (Moves move : moves) {
for (Class<? extends Movement> klass : klasses) { int num = count[move.ordinal()];
int num = count.get(klass); long nanoTime = timeConsumed[move.ordinal()];
long nanoTime = timeConsumed.get(klass); System.out.println(nanoTime / num + " " + move + " " + nanoTime / 1000000 + "ms " + num);
System.out.println(nanoTime / num + " " + klass + " " + nanoTime / 1000000 + "ms " + num); System.out.println(stateLookup[move.ordinal()] / num + " " + stateLookup[move.ordinal()]);
System.out.println(stateLookup.get(klass) / num + " " + stateLookup.get(klass)); System.out.println(posCreation[move.ordinal()] / num + " " + posCreation[move.ordinal()]);
System.out.println(posCreation.get(klass) / num + " " + posCreation.get(klass));
} }
if (cancelRequested) { if (cancelRequested) {
return Optional.empty(); return Optional.empty();
@@ -282,56 +263,4 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
logDebug("No path found =("); logDebug("No path found =(");
return Optional.empty(); 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 <T> 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;
}
}
} }
@@ -17,8 +17,7 @@
package baritone.pathing.calc; package baritone.pathing.calc;
import baritone.behavior.PathingBehavior; import baritone.api.pathing.goals.Goal;
import baritone.pathing.goals.Goal;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
@@ -115,9 +114,9 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
* @return The distance, squared * @return The distance, squared
*/ */
protected double getDistFromStartSq(PathNode n) { protected double getDistFromStartSq(PathNode n) {
int xDiff = n.pos.x - start.x; int xDiff = n.x - start.x;
int yDiff = n.pos.y - start.y; int yDiff = n.y - start.y;
int zDiff = n.pos.z - start.z; int zDiff = n.z - start.z;
return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff; 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, * for the node mapped to the specified pos. If no node is found,
* a new node is created. * a new node is created.
* *
* @param pos The pos to lookup
* @return The associated node * @return The associated node
* @see <a href="https://github.com/cabaletta/baritone/issues/107">Issue #107</a> * @see <a href="https://github.com/cabaletta/baritone/issues/107">Issue #107</a>
*/ */
protected PathNode getNodeAtPosition(BetterBlockPos pos) { protected PathNode getNodeAtPosition(int x, int y, int z) {
long hashCode = pos.hashCode; long hashCode = posHash(x, y, z);
PathNode node = map.get(hashCode); PathNode node = map.get(hashCode);
if (node == null) { if (node == null) {
node = new PathNode(pos, goal); node = new PathNode(x, y, z, goal);
map.put(hashCode, node); map.put(hashCode, node);
} }
return 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() { public static void forceCancel() {
PathingBehavior.INSTANCE.cancel();
currentlyRunning = null; currentlyRunning = null;
} }
public PathNode mostRecentNodeConsidered() {
return mostRecentConsidered;
}
public PathNode bestNodeSoFar() {
return bestSoFar[0];
}
public PathNode startNode() {
return startNode;
}
@Override @Override
public Optional<IPath> pathToMostRecentNodeConsidered() { public Optional<IPath> 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() { protected int mapSize() {
@@ -164,7 +197,12 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
continue; continue;
} }
if (getDistFromStartSq(bestSoFar[i]) > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared 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 // instead of returning bestSoFar[0], be less misleading
@@ -17,7 +17,7 @@
package baritone.pathing.calc; package baritone.pathing.calc;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
+20 -6
View File
@@ -17,8 +17,9 @@
package baritone.pathing.calc; package baritone.pathing.calc;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.Moves;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -60,8 +61,8 @@ class Path implements IPath {
private volatile boolean verified; private volatile boolean verified;
Path(PathNode start, PathNode end, int numNodes, Goal goal) { Path(PathNode start, PathNode end, int numNodes, Goal goal) {
this.start = start.pos; this.start = new BetterBlockPos(start.x, start.y, start.z);
this.end = end.pos; this.end = new BetterBlockPos(end.x, end.y, end.z);
this.numNodes = numNodes; this.numNodes = numNodes;
this.path = new ArrayList<>(); this.path = new ArrayList<>();
this.movements = new ArrayList<>(); this.movements = new ArrayList<>();
@@ -88,11 +89,11 @@ class Path implements IPath {
LinkedList<BetterBlockPos> tempPath = new LinkedList<>(); // Repeatedly inserting to the beginning of an arraylist is O(n^2) LinkedList<BetterBlockPos> tempPath = new LinkedList<>(); // Repeatedly inserting to the beginning of an arraylist is O(n^2)
LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end
while (!current.equals(start)) { while (!current.equals(start)) {
tempPath.addFirst(current.pos); tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z));
tempMovements.addFirst(current.previousMovement); tempMovements.addFirst(runBackwards(current.previous, current));
current = current.previous; 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 // 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<E> keeps track of length, then when we addall (which calls .toArray) it's able // inserting into a LinkedList<E> keeps track of length, then when we addall (which calls .toArray) it's able
// to performantly do that conversion since it knows the length. // to performantly do that conversion since it knows the length.
@@ -100,6 +101,19 @@ class Path implements IPath {
movements.addAll(tempMovements); 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. * Performs a series of checks to ensure that the assembly of the path went as expected.
*/ */
@@ -17,10 +17,8 @@
package baritone.pathing.calc; package baritone.pathing.calc;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts; import baritone.api.pathing.movement.ActionCosts;
import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos;
/** /**
* A node in the path, containing the cost and steps to get to it. * 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 * The position of this node
*/ */
final BetterBlockPos pos; final int x;
final int y;
/** final int z;
* The goal it's going towards
*/
final Goal goal;
/** /**
* Cached, should always be equal to goal.heuristic(pos) * Cached, should always be equal to goal.heuristic(pos)
@@ -62,12 +57,6 @@ public final class PathNode {
*/ */
PathNode previous; 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) * 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. * 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 int heapPosition;
public PathNode(BetterBlockPos pos, Goal goal) { public PathNode(int x, int y, int z, Goal goal) {
this.pos = pos;
this.previous = null; this.previous = null;
this.cost = ActionCosts.COST_INF; this.cost = ActionCosts.COST_INF;
this.goal = goal; this.estimatedCostToGoal = goal.heuristic(x, y, z);
this.estimatedCostToGoal = goal.heuristic(pos);
this.previousMovement = null;
this.isOpen = false; this.isOpen = false;
this.x = x;
this.y = y;
this.z = z;
} }
/** /**
@@ -96,7 +85,7 @@ public final class PathNode {
*/ */
@Override @Override
public int hashCode() { public int hashCode() {
return pos.hashCode() * 7 + 3; return (int) AbstractNodeCostSearch.posHash(x, y, z);
} }
@Override @Override
@@ -108,8 +97,9 @@ public final class PathNode {
// return false; // 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 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;
} }
} }
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
@@ -18,18 +18,19 @@
package baritone.pathing.movement; package baritone.pathing.movement;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.behavior.LookBehavior; import baritone.behavior.LookBehavior;
import baritone.behavior.LookBehaviorUtils; import baritone.behavior.LookBehaviorUtils;
import baritone.pathing.movement.MovementState.MovementStatus; import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.*; import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.BlockLiquid;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.chunk.EmptyChunk; import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -158,8 +159,8 @@ public abstract class Movement implements Helper, MovementHelper {
return true; return true;
} }
boolean somethingInTheWay = false; boolean somethingInTheWay = false;
for (BlockPos blockPos : positionsToBreak) { for (BetterBlockPos blockPos : positionsToBreak) {
if (!MovementHelper.canWalkThrough(blockPos)) { if (!MovementHelper.canWalkThrough(blockPos) && !(BlockStateInterface.getBlock(blockPos) instanceof BlockLiquid)) { // can't break liquid, so don't try
somethingInTheWay = true; somethingInTheWay = true;
Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos); Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos);
if (reachable.isPresent()) { if (reachable.isPresent()) {
@@ -218,60 +219,6 @@ public abstract class Movement implements Helper, MovementHelper {
currentState = new MovementState().setStatus(MovementStatus.PREPPING); 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. * Calculate latest movement state.
* Gets called once a tick. * Gets called once a tick.
@@ -309,7 +256,7 @@ public abstract class Movement implements Helper, MovementHelper {
return toBreakCached; return toBreakCached;
} }
List<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToBreak) { for (BetterBlockPos positionToBreak : positionsToBreak) {
if (!MovementHelper.canWalkThrough(positionToBreak)) { if (!MovementHelper.canWalkThrough(positionToBreak)) {
result.add(positionToBreak); result.add(positionToBreak);
} }
@@ -18,10 +18,10 @@
package baritone.pathing.movement; package baritone.pathing.movement;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.Rotation;
import baritone.behavior.LookBehaviorUtils; import baritone.behavior.LookBehaviorUtils;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.pathing.movement.movements.MovementDescend;
import baritone.pathing.movement.movements.MovementFall;
import baritone.utils.*; import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.*; import net.minecraft.block.*;
@@ -47,11 +47,12 @@ import java.util.Optional;
*/ */
public interface MovementHelper extends ActionCosts, Helper { 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(); 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 return b == Blocks.ICE // ice becomes water, and water can mess up the path
|| b instanceof BlockSilverfish // obvious reasons || b instanceof BlockSilverfish // obvious reasons
// call BlockStateInterface.get directly with x,y,z. no need to make 5 new BlockPos for no reason // 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 * @param pos
* @return * @return
*/ */
static boolean canWalkThrough(BlockPos pos) { static boolean canWalkThrough(BetterBlockPos pos) {
return canWalkThrough(pos, BlockStateInterface.get(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(); Block block = state.getBlock();
if (block == Blocks.AIR) { if (block == Blocks.AIR) { // early return for most common case
return true; return true;
} }
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL) { 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. // be opened by just interacting.
return block != Blocks.IRON_DOOR; return block != Blocks.IRON_DOOR;
} }
if (block instanceof BlockSnow || block instanceof BlockTrapDoor) { boolean snow = block instanceof BlockSnow;
// we've already checked doors boolean trapdoor = block instanceof BlockTrapDoor;
// so the only remaining dynamic isPassables are snow, fence gate, and trapdoor 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 // 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) // 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 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)) { if (BlockStateInterface.isFlowing(state)) {
return false; // Don't walk through flowing liquids return false; // Don't walk through flowing liquids
@@ -102,13 +120,16 @@ public interface MovementHelper extends ActionCosts, Helper {
if (Baritone.settings().assumeWalkOnWater.get()) { if (Baritone.settings().assumeWalkOnWater.get()) {
return false; 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) { if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
return false; return false;
} }
return block == Blocks.WATER || block == Blocks.FLOWING_WATER; 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 * @return
*/ */
static boolean fullyPassable(BlockPos pos) { 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(); Block block = state.getBlock();
if (block == Blocks.AIR) { if (block == Blocks.AIR) { // early return for most common case
return true; return true;
} }
// exceptions - blocks that are isPassable true, but we can't actually jump through // 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) { || block instanceof BlockEndPortal) {
return false; 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) { 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 // for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case // 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 // 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; * 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) // 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 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) { static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
@@ -226,9 +262,11 @@ public interface MovementHelper extends ActionCosts, Helper {
* *
* @return * @return
*/ */
static boolean canWalkOn(BetterBlockPos pos, IBlockState state) { static boolean canWalkOn(int x, int y, int z, IBlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
if (block == Blocks.AIR || block == Blocks.MAGMA) { 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; return false;
} }
if (state.isBlockNormalCube()) { if (state.isBlockNormalCube()) {
@@ -249,7 +287,7 @@ public interface MovementHelper extends ActionCosts, Helper {
if (BlockStateInterface.isWater(block)) { if (BlockStateInterface.isWater(block)) {
// since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()" // 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 // 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) { if (up == Blocks.WATERLILY) {
return true; return true;
} }
@@ -279,42 +317,70 @@ public interface MovementHelper extends ActionCosts, Helper {
return false; return false;
} }
static boolean canWalkOn(BetterBlockPos pos, IBlockState state) {
return canWalkOn(pos.x, pos.y, pos.z, state);
}
static boolean canWalkOn(BetterBlockPos pos) { 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) { 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 // 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(); 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); 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(); Block block = state.getBlock();
if (!canWalkThrough(position, state)) { if (!canWalkThrough(x, y, z, state)) {
if (!context.allowBreak()) { if (!context.allowBreak()) {
return COST_INF; return COST_INF;
} }
if (avoidBreaking(position, state)) { if (avoidBreaking(x, y, z, state)) {
return COST_INF;
}
if (block instanceof BlockLiquid) {
return COST_INF; 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 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); double strVsBlock = context.getToolSet().getStrVsBlock(state);
if (strVsBlock < 0) { if (strVsBlock <= 0) {
return COST_INF; return COST_INF;
} }
double result = m / strVsBlock; double result = m / strVsBlock;
if (includeFalling) { if (includeFalling) {
BlockPos up = position.up(); IBlockState above = BlockStateInterface.get(x, y + 1, z);
IBlockState above = BlockStateInterface.get(up);
if (above.getBlock() instanceof BlockFalling) { if (above.getBlock() instanceof BlockFalling) {
result += getMiningDurationTicks(context, up, above, true); result += getMiningDurationTicks(context, x, y + 1, z, above, true);
} }
} }
return result; return result;
@@ -400,57 +466,8 @@ public interface MovementHelper extends ActionCosts, Helper {
state.setTarget(new MovementTarget( state.setTarget(new MovementTarget(
new Rotation(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), new Rotation(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(pos), 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 false
)).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); )).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;
}
} }
@@ -17,8 +17,8 @@
package baritone.pathing.movement; package baritone.pathing.movement;
import baritone.api.utils.Rotation;
import baritone.utils.InputOverrideHandler.Input; import baritone.utils.InputOverrideHandler.Input;
import baritone.utils.Rotation;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import java.util.HashMap; import java.util.HashMap;
@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
@@ -28,7 +28,6 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils; import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling; import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -55,46 +54,54 @@ public class MovementAscend extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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) { if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
return COST_INF; return COST_INF;
} }
// we can jump from soul sand, but not from a bottom slab // we can jump from soul sand, but not from a bottom slab
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown); boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
IBlockState toPlace = BlockStateInterface.get(positionToPlace); IBlockState toPlace = BlockStateInterface.get(destX, y, destZ);
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace); boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
if (jumpingFromBottomSlab && !jumpingToBottomSlab) { if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab 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()) { if (!context.hasThrowaway()) {
return COST_INF; 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; return COST_INF;
} }
// TODO: add ability to place against .down() as well as the cardinal directions // 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 // 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 // Counterpoint to the above TODO ^ you should move then pillar instead of ascend
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
BlockPos against1 = positionToPlace.offset(HORIZONTALS[i]); int againstX = destX + HORIZONTALS[i].getXOffset();
if (against1.equals(src)) { int againstZ = destZ + HORIZONTALS[i].getZOffset();
if (againstX == x && againstZ == z) {
continue; continue;
} }
if (MovementHelper.canPlaceAgainst(against1)) { if (MovementHelper.canPlaceAgainst(againstX, y, againstZ)) {
return JUMP_ONE_BLOCK_COST + WALK_ONE_BLOCK_COST + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context); 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 // HOWEVER, we assume that we're standing in the start position
// that means that src and src.up(1) are both air // 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 // maybe they aren't now, but they will be by the time this starts
Block srcUp = BlockStateInterface.get(src.up(1)).getBlock(); if (!(BlockStateInterface.getBlock(x, y + 1, z) instanceof BlockFalling) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling)) {
Block srcUp2 = BlockStateInterface.get(src.up(2)).getBlock();
if (!(srcUp instanceof BlockFalling) || !(srcUp2 instanceof BlockFalling)) {
// if both of those are BlockFalling, that means that by standing on src // if both of those are BlockFalling, that means that by standing on src
// (the presupposition of this Movement) // (the presupposition of this Movement)
// we have necessarily already cleared the entire BlockFalling stack // 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 // 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 // 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; double walk;
if (jumpingToBottomSlab && !jumpingFromBottomSlab) { if (jumpingToBottomSlab) {
return walk + getTotalHardnessOfBlocksToBreak(context); // we don't hit space we just walk into the slab 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 if (srcUp2 == null) {
return Math.max(JUMP_ONE_BLOCK_COST, walk) + getTotalHardnessOfBlocksToBreak(context); 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 @Override
@@ -202,9 +235,9 @@ public class MovementAscend extends Movement {
} }
private boolean headBonkClear() { private boolean headBonkClear() {
BlockPos startUp = src.up(2); BetterBlockPos startUp = src.up(2);
for (int i = 0; i < 4; i++) { 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)) { if (!MovementHelper.canWalkThrough(check)) {
// We might bonk our head // We might bonk our head
return false; return false;
@@ -17,6 +17,7 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
@@ -25,10 +26,15 @@ import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.pathing.MoveResult;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import static baritone.utils.pathing.MoveResult.IMPOSSIBLE;
public class MovementDescend extends Movement { public class MovementDescend extends Movement {
private int numTicks = 0; private int numTicks = 0;
@@ -45,24 +51,111 @@ public class MovementDescend extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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) { 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(); totalCost += MovementHelper.getMiningDurationTicks(context, destX, y, destZ, false);
if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) { if (totalCost >= COST_INF) {
return 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) // 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; double walk = WALK_OFF_BLOCK_COST;
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance // use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk = WALK_ONE_OVER_SOUL_SAND_COST; 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 @Override
@@ -25,7 +25,6 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockMagma;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
@@ -53,40 +52,44 @@ public class MovementDiagonal extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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) { if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF; 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; return COST_INF;
} }
BetterBlockPos destDown = dest.down(); IBlockState destWalkOn = BlockStateInterface.get(destX, y - 1, destZ);
IBlockState destWalkOn = BlockStateInterface.get(destDown); if (!MovementHelper.canWalkOn(destX, y - 1, destZ, destWalkOn)) {
if (!MovementHelper.canWalkOn(destDown, destWalkOn)) {
return COST_INF; return COST_INF;
} }
double multiplier = WALK_ONE_BLOCK_COST; double multiplier = WALK_ONE_BLOCK_COST;
// For either possible soul sand, that affects half of our walking // 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; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
Block cuttingOver1 = BlockStateInterface.get(positionsToBreak[2].down()).getBlock(); Block cuttingOver1 = BlockStateInterface.get(x, y - 1, destZ).getBlock();
if (cuttingOver1 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver1)) { if (cuttingOver1 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver1)) {
return COST_INF; return COST_INF;
} }
Block cuttingOver2 = BlockStateInterface.get(positionsToBreak[4].down()).getBlock(); Block cuttingOver2 = BlockStateInterface.get(destX, y - 1, z).getBlock();
if (cuttingOver2 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver2)) { if (cuttingOver2 == Blocks.MAGMA || BlockStateInterface.isLava(cuttingOver2)) {
return COST_INF; return COST_INF;
} }
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); IBlockState pb0 = BlockStateInterface.get(x, y, destZ);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ);
IBlockState pb2 = BlockStateInterface.get(positionsToBreak[2]); IBlockState pb2 = BlockStateInterface.get(destX, y, z);
IBlockState pb3 = BlockStateInterface.get(positionsToBreak[3]); IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z);
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, true); double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false) + MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], pb2, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], pb3, 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) { if (optionA != 0 && optionB != 0) {
return COST_INF; return COST_INF;
} }
@@ -100,7 +103,7 @@ public class MovementDiagonal extends Movement {
return COST_INF; 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 // Ignore previous multiplier
// Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water // Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// Not even touching the blocks below // Not even touching the blocks below
@@ -43,17 +43,21 @@ public class MovementDownward extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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; return COST_INF;
} }
IBlockState d = BlockStateInterface.get(dest); IBlockState d = BlockStateInterface.get(x, y - 1, z);
Block td = d.getBlock(); Block td = d.getBlock();
boolean ladder = td == Blocks.LADDER || td == Blocks.VINE; boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
if (ladder) { if (ladder) {
return LADDER_DOWN_ONE_COST; return LADDER_DOWN_ONE_COST;
} else { } 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 // 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);
} }
} }
@@ -18,19 +18,20 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus; import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget; 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 baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block; import baritone.utils.pathing.MoveResult;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items; import net.minecraft.init.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -48,58 +49,11 @@ public class MovementFall extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock(); MoveResult result = MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z);
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { if (result.destY != dest.y) {
return COST_INF; return COST_INF; // doesn't apply to us, this position is a descend not a fall
} }
IBlockState fallOnto = BlockStateInterface.get(dest.down()); return result.cost;
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;
} }
@Override @Override
@@ -27,7 +27,7 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils; import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block; import baritone.utils.pathing.MoveResult;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
@@ -37,8 +37,10 @@ import net.minecraft.util.math.Vec3d;
import java.util.Objects; import java.util.Objects;
import static baritone.utils.pathing.MoveResult.IMPOSSIBLE;
public class MovementParkour extends Movement { 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 static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{};
private final EnumFacing direction; private final EnumFacing direction;
@@ -48,79 +50,81 @@ public class MovementParkour extends Movement {
super(src, src.offset(dir, dist), EMPTY); super(src, src.offset(dir, dist), EMPTY);
this.direction = dir; this.direction = dir;
this.dist = dist; this.dist = dist;
super.override(costFromJumpDistance(dist));
} }
public static MovementParkour generate(BetterBlockPos src, EnumFacing dir, CalculationContext context) { public static MovementParkour cost(CalculationContext context, BetterBlockPos src, EnumFacing direction) {
// MUST BE KEPT IN SYNC WITH calculateCost 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()) { 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)) { if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) {
return null; return IMPOSSIBLE;
} }
BetterBlockPos adjBlock = src.down().offset(dir); int xDiff = dir.getXOffset();
IBlockState adj = BlockStateInterface.get(adjBlock); 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 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) if (MovementHelper.canWalkOn(x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
return null; return IMPOSSIBLE;
} }
if (!MovementHelper.fullyPassable(src.offset(dir))) { if (!MovementHelper.fullyPassable(x + xDiff, y, z + zDiff)) {
return null; return IMPOSSIBLE;
} }
if (!MovementHelper.fullyPassable(src.up().offset(dir))) { if (!MovementHelper.fullyPassable(x + xDiff, y + 1, z + zDiff)) {
return null; return IMPOSSIBLE;
} }
if (!MovementHelper.fullyPassable(src.up(2).offset(dir))) { if (!MovementHelper.fullyPassable(x + xDiff, y + 2, z + zDiff)) {
return null; return IMPOSSIBLE;
} }
if (!MovementHelper.fullyPassable(src.up(2))) { if (!MovementHelper.fullyPassable(x, y + 2, z)) {
return null; return IMPOSSIBLE;
} }
for (int i = 2; i <= (context.canSprint() ? 4 : 3); i++) { 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? // TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly?
for (int y = 0; y < 4; y++) { for (int y2 = 0; y2 < 4; y2++) {
if (!MovementHelper.fullyPassable(dest.up(y))) { if (!MovementHelper.fullyPassable(x + xDiff * i, y + y2, z + zDiff * i)) {
return null; return IMPOSSIBLE;
} }
} }
if (MovementHelper.canWalkOn(dest.down())) { if (MovementHelper.canWalkOn(x + xDiff * i, y - 1, z + zDiff * i)) {
return new MovementParkour(src, i, dir); return new MoveResult(x + xDiff * i, y, z + zDiff * i, costFromJumpDistance(i));
} }
} }
if (!context.canSprint()) { if (!context.canSprint()) {
return null; return IMPOSSIBLE;
} }
if (!Baritone.settings().allowParkourPlace.get()) { if (!Baritone.settings().allowParkourPlace.get()) {
return null; return IMPOSSIBLE;
} }
BlockPos dest = src.offset(dir, 4); int destX = x + 4 * xDiff;
BlockPos positionToPlace = dest.down(); int destZ = z + 4 * zDiff;
IBlockState toPlace = BlockStateInterface.get(positionToPlace); IBlockState toPlace = BlockStateInterface.get(destX, y - 1, destZ);
if (!context.hasThrowaway()) { if (!context.hasThrowaway()) {
return null; return IMPOSSIBLE;
} }
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 - 1, destZ, toPlace)) {
return null; return IMPOSSIBLE;
} }
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
if (against1.up().equals(src.offset(dir, 3))) { // we can't turn around that fast 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; continue;
} }
if (MovementHelper.canPlaceAgainst(against1)) { if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) {
// holy jesus we gonna do it return new MoveResult(destX, y, destZ, costFromJumpDistance(i) + context.placeBlockCost());
MovementParkour ret = new MovementParkour(src, 4, dir);
ret.override(costFromJumpDistance(4) + context.placeBlockCost());
return ret;
} }
} }
return null; return IMPOSSIBLE;
} }
private static double costFromJumpDistance(int dist) { private static double costFromJumpDistance(int dist) {
@@ -139,54 +143,11 @@ public class MovementParkour extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
// MUST BE KEPT IN SYNC WITH generate MoveResult res = cost(context, src.x, src.y, src.z, direction);
if (!context.canSprint() && dist >= 4) { if (res.destX != dest.x || res.destZ != dest.z) {
return COST_INF; return COST_INF;
} }
boolean placing = false; return res.cost;
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?");
} }
@Override @Override
@@ -209,7 +170,7 @@ public class MovementParkour extends Movement {
if (!MovementHelper.canWalkOn(dest.down())) { if (!MovementHelper.canWalkOn(dest.down())) {
BlockPos positionToPlace = dest.down(); BlockPos positionToPlace = dest.down();
for (int i = 0; i < 5; i++) { 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 if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast
continue; continue;
} }
@@ -17,13 +17,13 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.api.utils.Rotation;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.Rotation;
import baritone.utils.Utils; import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.*; import net.minecraft.block.*;
@@ -48,9 +48,13 @@ public class MovementPillar extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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; 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 (!ladder) {
if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) { if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) {
return COST_INF; return COST_INF;
@@ -61,28 +65,27 @@ public class MovementPillar extends Movement {
} }
} }
} }
if (!context.hasThrowaway() && !ladder) {
return COST_INF;
}
if (fromDown instanceof BlockVine) { if (fromDown instanceof BlockVine) {
if (getAgainst(src) == null) { if (!hasAgainst(x, y, z)) {
return COST_INF; return COST_INF;
} }
} }
BlockPos toBreakPos = src.up(2); IBlockState toBreak = BlockStateInterface.get(x, y + 2, z);
IBlockState toBreak = BlockStateInterface.get(toBreakPos);
Block toBreakBlock = toBreak.getBlock(); Block toBreakBlock = toBreak.getBlock();
if (toBreakBlock instanceof BlockFenceGate) { if (toBreakBlock instanceof BlockFenceGate) {
return COST_INF; return COST_INF;
} }
Block srcUp = null; Block srcUp = null;
if (BlockStateInterface.isWater(toBreakBlock) && BlockStateInterface.isWater(fromDown)) { if (BlockStateInterface.isWater(toBreakBlock) && BlockStateInterface.isWater(fromDown)) {
srcUp = BlockStateInterface.get(dest).getBlock(); srcUp = BlockStateInterface.get(x, y + 1, z).getBlock();
if (BlockStateInterface.isWater(srcUp)) { if (BlockStateInterface.isWater(srcUp)) {
return LADDER_UP_ONE_COST; 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) { if (hardness >= COST_INF) {
return COST_INF; return COST_INF;
} }
@@ -90,12 +93,11 @@ public class MovementPillar extends Movement {
if (toBreakBlock instanceof BlockLadder || toBreakBlock instanceof BlockVine) { 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 hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it
} else { } else {
BlockPos chkPos = src.up(3); IBlockState check = BlockStateInterface.get(x, y + 3, z);
IBlockState check = BlockStateInterface.get(chkPos);
if (check.getBlock() instanceof BlockFalling) { if (check.getBlock() instanceof BlockFalling) {
// see MovementAscend's identical check for breaking a falling block above our head // see MovementAscend's identical check for breaking a falling block above our head
if (srcUp == null) { if (srcUp == null) {
srcUp = BlockStateInterface.get(dest).getBlock(); srcUp = BlockStateInterface.get(x, y + 1, z).getBlock();
} }
if (!(toBreakBlock instanceof BlockFalling) || !(srcUp instanceof BlockFalling)) { if (!(toBreakBlock instanceof BlockFalling) || !(srcUp instanceof BlockFalling)) {
return COST_INF; 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) { public static BlockPos getAgainst(BlockPos vine) {
if (BlockStateInterface.get(vine.north()).isBlockNormalCube()) { if (BlockStateInterface.get(vine.north()).isBlockNormalCube()) {
return vine.north(); return vine.north();
@@ -18,6 +18,7 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.behavior.LookBehaviorUtils; import baritone.behavior.LookBehaviorUtils;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
@@ -25,7 +26,6 @@ import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.Rotation;
import baritone.utils.Utils; import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.*; import net.minecraft.block.*;
@@ -57,11 +57,15 @@ public class MovementTraverse extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); return cost(context, src.x, src.y, src.z, dest.x, dest.z);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); }
IBlockState destOn = BlockStateInterface.get(positionToPlace);
Block srcDown = BlockStateInterface.getBlock(src.down()); public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
if (MovementHelper.canWalkOn(positionToPlace, destOn)) {//this is a walk, not a bridge 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; double WC = WALK_ONE_BLOCK_COST;
if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) { if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC = WALK_ONE_IN_WATER_COST; 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; 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) { if (hardness1 >= COST_INF) {
return 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 (hardness1 == 0 && hardness2 == 0) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) { 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 // 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) { if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
return COST_INF; 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()); boolean throughWater = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock());
if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) { if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) {
return COST_INF; return COST_INF;
@@ -103,15 +107,21 @@ public class MovementTraverse extends Movement {
if (!context.hasThrowaway()) { if (!context.hasThrowaway()) {
return COST_INF; 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; double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
BlockPos against1 = dest.offset(HORIZONTALS[i]); int againstX = destX + HORIZONTALS[i].getXOffset();
if (against1.equals(src)) { int againstZ = destZ + HORIZONTALS[i].getZOffset();
if (againstX == x && againstZ == z) {
continue; continue;
} }
against1 = against1.down(); if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) {
if (MovementHelper.canPlaceAgainst(against1)) { return WC + context.placeBlockCost() + hardness1 + hardness2;
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
} }
} }
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) { 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 return COST_INF; // this is obviously impossible
} }
WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking 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; return COST_INF;
// Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock()); // 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 // 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 // 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 yawToDest = Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(dest, world())).getYaw();
float pitchToBreak = state.getTarget().getRotation().get().getSecond(); float pitchToBreak = state.getTarget().getRotation().get().getPitch();
state.setTarget(new MovementState.MovementTarget(new Rotation(yawToDest, pitchToBreak), true)); state.setTarget(new MovementState.MovementTarget(new Rotation(yawToDest, pitchToBreak), true));
return state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); return state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
@@ -17,7 +17,7 @@
package baritone.pathing.path; package baritone.pathing.path;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
@@ -18,7 +18,7 @@
package baritone.pathing.path; package baritone.pathing.path;
import baritone.Baritone; import baritone.Baritone;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.Utils; import baritone.utils.Utils;
@@ -19,6 +19,7 @@ package baritone.pathing.path;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.event.events.TickEvent; import baritone.api.event.events.TickEvent;
import baritone.api.pathing.movement.ActionCosts;
import baritone.pathing.movement.*; import baritone.pathing.movement.*;
import baritone.pathing.movement.movements.*; import baritone.pathing.movement.movements.*;
import baritone.utils.BlockStateInterface; 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)) { 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 // avoid the Wrong Y coordinate bug
// TODO add a timer here
new MovementDownward(whereAmI, whereShouldIBe).update(); new MovementDownward(whereAmI, whereShouldIBe).update();
return false; return false;
} }
@@ -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 <https://www.gnu.org/licenses/>.
*/
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");
}
}
}
}
@@ -46,7 +46,9 @@ public final class BlockBreakHelper implements Helper {
} }
public static void stopBreakingBlock() { public static void stopBreakingBlock() {
mc.playerController.resetBlockRemoving(); if (mc.playerController != null) {
mc.playerController.resetBlockRemoving();
}
lastBlock = null; lastBlock = null;
} }
} }
@@ -60,6 +60,7 @@ public class BlockStateInterface implements Helper {
// if it's the same chunk as last time // if it's the same chunk as last time
// we can just skip the mc.world.getChunk lookup // we can just skip the mc.world.getChunk lookup
// which is a Long2ObjectOpenHashMap.get // which is a Long2ObjectOpenHashMap.get
// see issue #113
if (cached != null && cached.x == x >> 4 && cached.z == z >> 4) { if (cached != null && cached.x == x >> 4 && cached.z == z >> 4) {
numTimesChunkSucceeded++; numTimesChunkSucceeded++;
return cached.getBlockState(x, y, z); return cached.getBlockState(x, y, z);
@@ -92,6 +93,32 @@ public class BlockStateInterface implements Helper {
return type; 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() { public static void clearCachedChunk() {
prev = null; prev = null;
prevCached = null; prevCached = null;
@@ -101,6 +128,9 @@ public class BlockStateInterface implements Helper {
return get(pos).getBlock(); 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 * Returns whether or not the specified block is
@@ -18,23 +18,20 @@
package baritone.utils; package baritone.utils;
import baritone.Baritone; import baritone.Baritone;
import baritone.Settings; import baritone.api.Settings;
import baritone.api.behavior.Behavior; import baritone.api.cache.IWaypoint;
import baritone.api.event.events.ChatEvent; 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.FollowBehavior;
import baritone.behavior.MineBehavior; import baritone.behavior.MineBehavior;
import baritone.behavior.PathingBehavior; import baritone.behavior.PathingBehavior;
import baritone.cache.ChunkPacker; import baritone.cache.ChunkPacker;
import baritone.cache.Waypoint; import baritone.cache.Waypoint;
import baritone.cache.WorldProvider; import baritone.cache.WorldProvider;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.goals.*; import baritone.pathing.movement.*;
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 net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@@ -43,6 +40,8 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ExampleBaritoneControl extends Behavior implements Helper { public class ExampleBaritoneControl extends Behavior implements Helper {
@@ -185,7 +184,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
Chunk chunk = cli.getLoadedChunk(x, z); Chunk chunk = cli.getLoadedChunk(x, z);
if (chunk != null) { if (chunk != null) {
count++; 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; return;
} }
if (msg.equals("forcecancel")) { if (msg.equals("forcecancel")) {
MineBehavior.INSTANCE.cancel();
FollowBehavior.INSTANCE.cancel();
PathingBehavior.INSTANCE.cancel();
AbstractNodeCostSearch.forceCancel(); AbstractNodeCostSearch.forceCancel();
PathingBehavior.INSTANCE.forceCancel();
event.cancel(); event.cancel();
logDirect("ok force canceled"); logDirect("ok force canceled");
return; return;
@@ -269,20 +272,20 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
return; return;
} }
if (msg.equals("reloadall")) { if (msg.equals("reloadall")) {
WorldProvider.INSTANCE.getCurrentWorld().cache.reloadAllFromDisk(); WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().reloadAllFromDisk();
logDirect("ok"); logDirect("ok");
event.cancel(); event.cancel();
return; return;
} }
if (msg.equals("saveall")) { if (msg.equals("saveall")) {
WorldProvider.INSTANCE.getCurrentWorld().cache.save(); WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().save();
logDirect("ok"); logDirect("ok");
event.cancel(); event.cancel();
return; return;
} }
if (msg.startsWith("find")) { if (msg.startsWith("find")) {
String blockType = msg.substring(4).trim(); String blockType = msg.substring(4).trim();
LinkedList<BlockPos> locs = WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(blockType, 1, 4); LinkedList<BlockPos> locs = WorldProvider.INSTANCE.getCurrentWorld().getCachedWorld().getLocationsOf(blockType, 1, 4);
logDirect("Have " + locs.size() + " locations"); logDirect("Have " + locs.size() + " locations");
for (BlockPos pos : locs) { for (BlockPos pos : locs) {
Block actually = BlockStateInterface.get(pos).getBlock(); Block actually = BlockStateInterface.get(pos).getBlock();
@@ -297,8 +300,9 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
String[] blockTypes = msg.substring(4).trim().split(" "); String[] blockTypes = msg.substring(4).trim().split(" ");
try { try {
int quantity = Integer.parseInt(blockTypes[1]); int quantity = Integer.parseInt(blockTypes[1]);
ChunkPacker.stringToBlock(blockTypes[0]).hashCode(); Block block = ChunkPacker.stringToBlock(blockTypes[0]);
MineBehavior.INSTANCE.mine(quantity, blockTypes[0]); Objects.requireNonNull(block);
MineBehavior.INSTANCE.mine(quantity, block);
logDirect("Will mine " + quantity + " " + blockTypes[0]); logDirect("Will mine " + quantity + " " + blockTypes[0]);
event.cancel(); event.cancel();
return; return;
@@ -339,22 +343,38 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel(); event.cancel();
return; return;
} }
Set<Waypoint> waypoints = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getByTag(tag); Set<IWaypoint> waypoints = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getByTag(tag);
// might as well show them from oldest to newest // might as well show them from oldest to newest
List<Waypoint> sorted = new ArrayList<>(waypoints); List<IWaypoint> sorted = new ArrayList<>(waypoints);
sorted.sort(Comparator.comparingLong(Waypoint::creationTimestamp)); sorted.sort(Comparator.comparingLong(IWaypoint::getCreationTimestamp));
logDirect("Waypoints under tag " + tag + ":"); logDirect("Waypoints under tag " + tag + ":");
for (Waypoint waypoint : sorted) { for (IWaypoint waypoint : sorted) {
logDirect(waypoint.toString()); logDirect(waypoint.toString());
} }
event.cancel(); event.cancel();
return; return;
} }
if (msg.startsWith("save")) { 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(); 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; return;
} }
if (msg.startsWith("goto")) { if (msg.startsWith("goto")) {
@@ -364,31 +384,37 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
waypointType = waypointType.substring(0, waypointType.length() - 1); waypointType = waypointType.substring(0, waypointType.length() - 1);
} }
Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType); Waypoint.Tag tag = Waypoint.Tag.fromString(waypointType);
IWaypoint waypoint;
if (tag == null) { if (tag == null) {
String mining = waypointType; String mining = waypointType;
Block block = ChunkPacker.stringToBlock(mining); Block block = ChunkPacker.stringToBlock(mining);
//logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase()); //logDirect("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
event.cancel(); event.cancel();
if (block == null) { 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<BlockPos> 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; return;
} }
List<BlockPos> locs = MineBehavior.scanFor(Collections.singletonList(block), 64); } else {
if (locs.isEmpty()) { waypoint = WorldProvider.INSTANCE.getCurrentWorld().getWaypoints().getMostRecentByTag(tag);
logDirect("No locations for " + mining + " known, cancelling"); if (waypoint == null) {
logDirect("None saved for tag " + tag);
event.cancel();
return; 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); Goal goal = new GoalBlock(waypoint.getLocation());
if (waypoint == null) {
logDirect("None saved for tag " + tag);
event.cancel();
return;
}
Goal goal = new GoalBlock(waypoint.location);
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
if (!PathingBehavior.INSTANCE.path()) { if (!PathingBehavior.INSTANCE.path()) {
if (!goal.isInGoal(playerFeet())) { if (!goal.isInGoal(playerFeet())) {
@@ -399,7 +425,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
return; return;
} }
if (msg.equals("spawn") || msg.equals("bed")) { 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) { if (waypoint == null) {
BlockPos spawnPoint = player().getBedLocation(); BlockPos spawnPoint = player().getBedLocation();
// for some reason the default spawnpoint is underground sometimes // 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); logDirect("spawn not saved, defaulting to world spawn. set goal to " + goal);
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
} else { } else {
Goal goal = new GoalBlock(waypoint.location); Goal goal = new GoalBlock(waypoint.getLocation());
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
logDirect("Set goal to most recent bed " + goal); logDirect("Set goal to most recent bed " + goal);
} }
@@ -415,17 +441,17 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
return; return;
} }
if (msg.equals("sethome")) { 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."); logDirect("Saved. Say home to set goal.");
event.cancel(); event.cancel();
return; return;
} }
if (msg.equals("home")) { 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) { if (waypoint == null) {
logDirect("home not saved"); logDirect("home not saved");
} else { } else {
Goal goal = new GoalBlock(waypoint.location); Goal goal = new GoalBlock(waypoint.getLocation());
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
PathingBehavior.INSTANCE.path(); PathingBehavior.INSTANCE.path();
logDirect("Going to saved home " + goal); logDirect("Going to saved home " + goal);
@@ -434,8 +460,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
return; return;
} }
if (msg.equals("costs")) { if (msg.equals("costs")) {
Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext()); List<Movement> moves = Stream.of(Moves.values()).map(x -> x.apply0(playerFeet())).collect(Collectors.toCollection(ArrayList::new));
List<Movement> moves = new ArrayList<>(Arrays.asList(movements));
while (moves.contains(null)) { while (moves.contains(null)) {
moves.remove(null); moves.remove(null);
} }
+6 -5
View File
@@ -18,6 +18,7 @@
package baritone.utils; package baritone.utils;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.BlockSlab; import net.minecraft.block.BlockSlab;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -34,6 +35,11 @@ import net.minecraft.util.text.TextFormatting;
*/ */
public interface Helper { public interface Helper {
/**
* Instance of {@link Helper}. Used for static-context reference.
*/
Helper HELPER = new Helper() {};
ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format( ITextComponent MESSAGE_PREFIX = new TextComponentString(String.format(
"%s[%sBaritone%s]%s", "%s[%sBaritone%s]%s",
TextFormatting.DARK_PURPLE, TextFormatting.DARK_PURPLE,
@@ -98,9 +104,4 @@ public interface Helper {
component.appendSibling(new TextComponentString(" " + message)); component.appendSibling(new TextComponentString(" " + message));
Baritone.settings().logger.get().accept(component); Baritone.settings().logger.get().accept(component);
} }
default void addToChat(ITextComponent msg) {
mc.ingameGUI.getChatGUI().printChatMessage(msg);
}
} }
@@ -18,12 +18,12 @@
package baritone.utils; package baritone.utils;
import baritone.Baritone; import baritone.Baritone;
import baritone.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.pathing.goals.GoalComposite; import baritone.api.pathing.goals.GoalComposite;
import baritone.pathing.goals.GoalTwoBlocks; import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.pathing.goals.GoalXZ; import baritone.api.pathing.goals.GoalXZ;
import baritone.pathing.path.IPath; import baritone.pathing.path.IPath;
import baritone.utils.interfaces.IGoalRenderPos; import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
@@ -17,6 +17,7 @@
package baritone.utils; package baritone.utils;
import baritone.api.utils.Rotation;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -30,6 +31,18 @@ public final class RayTraceUtils implements Helper {
private RayTraceUtils() {} 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) { public static RayTraceResult simulateRayTrace(float yaw, float pitch) {
RayTraceResult oldTrace = mc.objectMouseOver; RayTraceResult oldTrace = mc.objectMouseOver;
float oldYaw = mc.player.rotationYaw; float oldYaw = mc.player.rotationYaw;
@@ -48,6 +61,14 @@ public final class RayTraceUtils implements Helper {
return result; 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) { public static RayTraceResult rayTraceTowards(Rotation rotation) {
double blockReachDistance = mc.playerController.getBlockReachDistance(); double blockReachDistance = mc.playerController.getBlockReachDistance();
Vec3d start = mc.player.getPositionEyes(1.0F); Vec3d start = mc.player.getPositionEyes(1.0F);
+6 -6
View File
@@ -17,6 +17,7 @@
package baritone.utils; package baritone.utils;
import baritone.api.utils.Rotation;
import net.minecraft.block.BlockFire; import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP; 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.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import static baritone.utils.Helper.HELPER;
/** /**
* @author Brady * @author Brady
* @since 8/1/2018 12:56 AM * @since 8/1/2018 12:56 AM
@@ -96,10 +99,7 @@ public final class Utils {
} }
public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) { public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) {
return new Rotation( return target.subtract(current).normalize().add(current);
MathHelper.wrapDegrees(target.getFirst() - current.getFirst()) + current.getFirst(),
MathHelper.wrapDegrees(target.getSecond() - current.getSecond()) + current.getSecond()
);
} }
public static Vec3d vec3dFromBlockPos(BlockPos orig) { public static Vec3d vec3dFromBlockPos(BlockPos orig) {
@@ -114,12 +114,12 @@ public final class Utils {
} }
public static double playerDistanceToCenter(BlockPos pos) { public static double playerDistanceToCenter(BlockPos pos) {
EntityPlayerSP player = (new Helper() {}).player(); EntityPlayerSP player = HELPER.player();
return distanceToCenter(pos, player.posX, player.posY, player.posZ); return distanceToCenter(pos, player.posX, player.posY, player.posZ);
} }
public static double playerFlatDistanceToCenter(BlockPos pos) { 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); return distanceToCenter(pos, player.posX, pos.getY() + 0.5, player.posZ);
} }
@@ -17,6 +17,7 @@
package baritone.utils.pathing; package baritone.utils.pathing;
import baritone.pathing.calc.AbstractNodeCostSearch;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@@ -51,22 +52,7 @@ public final class BetterBlockPos extends BlockPos {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
/* this.hashCode = AbstractNodeCostSearch.posHash(x, y, 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;
} }
public BetterBlockPos(double x, double y, double z) { public BetterBlockPos(double x, double y, double z) {
@@ -129,7 +115,7 @@ public final class BetterBlockPos extends BlockPos {
@Override @Override
public BetterBlockPos down(int amt) { public BetterBlockPos down(int amt) {
// see comment in up() // see comment in up()
return new BetterBlockPos(x, y - amt, z); return amt == 0 ? this : new BetterBlockPos(x, y - amt, z);
} }
@Override @Override
@@ -140,7 +126,50 @@ public final class BetterBlockPos extends BlockPos {
@Override @Override
public BetterBlockPos offset(EnumFacing dir, int dist) { public BetterBlockPos offset(EnumFacing dir, int dist) {
if (dist == 0) {
return this;
}
Vec3i vec = dir.getDirectionVec(); Vec3i vec = dir.getDirectionVec();
return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist); 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);
}
} }
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}
@@ -17,10 +17,8 @@
package baritone.pathing.calc.openset; package baritone.pathing.calc.openset;
import baritone.api.pathing.goals.Goal;
import baritone.pathing.calc.PathNode; 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.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@@ -91,14 +89,14 @@ public class OpenSetsTest {
// can't use an existing goal // can't use an existing goal
// because they use Baritone.settings() // because they use Baritone.settings()
// and we can't do that because Minecraft itself isn't initted // 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 @Override
public boolean isInGoal(BlockPos pos) { public boolean isInGoal(int x, int y, int z) {
return false; return false;
} }
@Override @Override
public double heuristic(BlockPos pos) { public double heuristic(int x, int y, int z) {
return 0; return 0;
} }
}); });
@@ -17,6 +17,7 @@
package baritone.pathing.goals; package baritone.pathing.goals;
import baritone.api.pathing.goals.GoalGetToBlock;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.junit.Test; import org.junit.Test;
@@ -19,10 +19,10 @@ package baritone.pathing.movement;
import org.junit.Test; import org.junit.Test;
import static baritone.pathing.movement.ActionCostsButOnlyTheOnesThatMakeMickeyDieInside.*; import static baritone.api.pathing.movement.ActionCosts.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
public class ActionCostsButOnlyTheOnesThatMakeMickeyDieInsideTest { public class ActionCostsTest {
@Test @Test
public void testFallNBlocksCost() { public void testFallNBlocksCost() {
assertEquals(FALL_N_BLOCKS_COST.length, 257); // Fall 0 blocks through fall 256 blocks assertEquals(FALL_N_BLOCKS_COST.length, 257); // Fall 0 blocks through fall 256 blocks
@@ -17,14 +17,17 @@
package baritone.utils.pathing; package baritone.utils.pathing;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BetterBlockPosTest { 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() { public void benchMulti() {
System.out.println("Benching up()"); System.out.println("Benching up()");
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
@@ -37,7 +40,40 @@ public class BetterBlockPosTest {
benchN(); benchN();
assertTrue(i<10); 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() { public void benchOne() {
@@ -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 <https://www.gnu.org/licenses/>.
*/
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]));
}
}
}