diff --git a/.gitignore b/.gitignore
index 564974df..de408ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,8 @@
**/*.swp
run/
+autotest/
+dist/
# Gradle
build/
diff --git a/.travis.yml b/.travis.yml
index c54706cf..a8344ba0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ 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 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; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient"
- docker cp baritone:/code/dist dist
- ls dist
- cat dist/checksums.txt
diff --git a/Dockerfile b/Dockerfile
index ac36eea5..bec43d69 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,16 +13,12 @@ RUN apt install --target-release jessie-backports \
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
+COPY . /code
WORKDIR /code
+# this .deb is specially patched to support lwjgl
+# source: https://github.com/tectonicus/tectonicus/issues/60#issuecomment-154239173
+RUN dpkg -i scripts/xvfb_1.16.4-1_amd64.deb
+
RUN ./gradlew build
\ No newline at end of file
diff --git a/FEATURES.md b/FEATURES.md
index 172b2f87..cd2a90fe 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -10,16 +10,19 @@
- **Falling blocks** Baritone understands the costs of breaking blocks with falling blocks on top, and includes all of their break costs. Additionally, since it avoids breaking any blocks touching a liquid, it won't break the bottom of a gravel stack below a lava lake (anymore).
- **Avoiding dangerous blocks** Obviously, it knows not to walk through fire or on magma, not to corner over lava (that deals some damage), not to break any blocks touching a liquid (it might drown), etc.
- **Parkour** Sprint jumping over 1, 2, or 3 block gaps
+- **Parkour place** Sprint jumping over a 3 block gap and placing the block to land on while executing the jump. It's really cool.
# Pathing method
-Baritone uses a modified version of A*.
+Baritone uses A*, with some modifications:
-- **Incremental cost backoff** Since most of the time Baritone only knows the terrain up to the render distance, it can't calculate a full path to the goal. Therefore it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a write-up that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
+- **Segmented calculation** Traditional A* calculates until the most promising node is in the goal, however in the environment of Minecraft with a limited render distance, we don't know the environment all the way to our goal. Baritone has three possible ways for path calculation to end: finding a path all the way to the goal, running out of time, or getting to the render distance. In the latter two scenarios, the selection of which segment to actually execute falls to the next item (incremental cost backoff). Whenever the path calculation thread finds that the best / most promising node is at the edge of loaded chunks, it increments a counter. If this happens more than 50 times (configurable), path calculation exits early. This happens with very low render distances. Otherwise, calculation continues until the timeout is hit (also configurable) or we find a path all the way to the goal.
+- **Incremental cost backoff** When path calculation exits early without getting all the way to the goal, Baritone it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a write-up that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
- **Minimum improvement repropagation** The pathfinder ignores alternate routes that provide minimal improvements (less than 0.01 ticks of improvement), because the calculation cost of repropagating this to all connected nodes is much higher than the half-millisecond path time improvement it would get.
-- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment slightly, as a tiebreaker. This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. Example
+- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment. The cost is decreased heavily, but is still positive (this won't cause it to backtrack if it doesn't need to). This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. Example
+- **Backtrack detection and pausing** While path calculation happens on a separate thread, the main game thread has access to the latest node considered, and the best path so far (those are rendered light blue and dark blue respectively). When the current best path (rendered dark blue) passes through the player's current position on the current path segment, path execution is paused (if it's safe to do so), because there's no point continuing forward if we're about to turn around and go back that same way. Note that the current best path as reported by the path calculation thread takes into account the incremental cost backoff system, so it's accurate to what the path calculation thread will actually pick once it finishes.
# Configuring Baritone
-All the settings and documentation are here.
+All the settings and documentation are here.
To change a boolean setting, just say its name in chat (for example saying `allowBreak` toggles whether Baritone will consider breaking blocks). For a numeric setting, say its name then the new value (like `pathTimeoutMS 250`). It's case insensitive.
# Goals
@@ -30,6 +33,7 @@ The pathing goal can be set to any of these options:
- **GoalTwoBlocks** a block position that the player should stand in, either at foot or eye level
- **GoalGetToBlock** a block position that the player should stand adjacent to, below, or on top of
- **GoalNear** a block position that the player should get within a certain radius of, used for following entities
+- **GoalAxis** a block position on an axis or diagonal axis (so x=0, z=0, or x=z), and y=120 (configurable)
And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one of which satisfies the goal. For example, `mine diamond_ore` creates a `GoalComposite` of `GoalTwoBlocks`s for every diamond ore location it knows of.
@@ -38,7 +42,6 @@ And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one o
Things it doesn't have yet
- Trapdoors
- Sprint jumping in a 1x2 corridor
-- Parkour (jumping over gaps of any length) [IN PROGRESS]
See issues for more.
diff --git a/IMPACT.md b/IMPACT.md
index e8430ab5..cc12252e 100644
--- a/IMPACT.md
+++ b/IMPACT.md
@@ -1,89 +1 @@
-# Integration between Baritone and Impact
-Impact 4.4 will have Baritone included on release, however, if you're impatient, you can install Baritone into Impact 4.3 right now!
-
-## An Introduction
-There are some basic steps to getting Baritone setup with Impact.
-- Acquiring a build of Baritone
-- Placing Baritone in the libraries directory
-- Modifying the Impact Profile JSON to run baritone
-- How to use Baritone
-
-## Acquiring a build of Baritone
-There are 3 methods of acquiring a build of Baritone (While it is still in development)
-
-### Official Release (Not always up to date)
-https://github.com/cabaletta/baritone/releases
-
-For Impact 4.3, there is no Baritone integration yet, so you will want `baritone-standalone-X.Y.Z.jar`.
-
-Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`.
-
-### Building Baritone yourself
-There are a few steps to this
-- Clone this repository
-- Setup the project as instructed in the README
-- Run the ``build`` gradle task. You can either do this using IntelliJ's gradle UI or through a
-command line
- - Windows: ``gradlew build``
- - Mac/Linux: ``./gradlew build``
-- The build should be exported into ``/build/libs/baritone-X.Y.Z.jar``
-
-### Cutting Edge Release
-If you want to trust @Plutie#9079, you can download an automatically generated build of the latest commit
-from his Jenkins server, found here.
-
-## Placing Baritone in the libraries directory
-``/libraries`` is a neat directory in your Minecraft Installation Directory
-that contains all of the dependencies that are required from the game and some mods. This is where we will be
-putting baritone.
-- Locate the ``libraries`` folder, it should be in the Minecraft Installation Directory
-- Create 3 new subdirectories starting from ``libraries``
- - ``cabaletta``
- - ``baritone``
- - ``X.Y.Z``
- - Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder
- - The full path should look like ``/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar``
-
-## Modifying the Impact Profile JSON to run baritone
-The final step is "registering" the Baritone library with Impact, so that it loads on launch.
-- Ensure your Minecraft launcher is closed
-- Navigate back to the Minecraft Installation Directory
-- Find the ``versions`` directory, and open in
-- In here there should be a ``1.12.2-Impact_4.3`` folder.
- - If you don't have any Impact folder or have a version older than 4.3, you can download Impact here.
-- Open the folder and inside there should be a file called ``1.12.2-Impact_4.3.json``
-- Open the JSON file with a text editor that supports your system's line endings
- - For example, Notepad on Windows likely will NOT work for this. You should instead use a Text Editor like
- Notepad++ if you're on Windows. (For other systems, I'm not sure
- what would work the best so you may have to do some research.)
-- Find the ``libraries`` array in the JSON. It should look something like this.
- ```
- "libraries": [
- {
- "name": "net.minecraft:launchwrapper:1.12"
- },
- {
- "name": "com.github.ImpactDevelopment:Impact:4.3-1.12.2",
- "url": "https://impactdevelopment.github.io/maven/"
- },
- {
- "name": "com.github.ImpactDeveloment:ClientAPI:3.0.2",
- "url": "https://impactdevelopment.github.io/maven/"
- },
- ...
- ```
-- Create a new object in the array, between the ``Impact`` and ``ClientAPI`` dependencies preferably.
- ```
- {
- "name": "cabaletta:baritone:X.Y.Z"
- },
- ```
-- Now find the ``"minecraftArguments": "..."`` text near the top.
-- At the very end of the quotes where it says ``--tweakClass clientapi.load.ClientTweaker"``, add on the following so it looks like:
- - ``--tweakClass clientapi.load.ClientTweaker --tweakClass baritone.launch.BaritoneTweakerOptifine"``
-- If you didn't close your launcher for this step, restart it now.
-- You can now launch Impact 4.3 as normal, and Baritone should start up
-
- ## How to use Baritone
- Instructions on how to use Baritone are limited, and you may have to read a little bit of code (Really nothing much
- just plain English), you can view that here.
+Impact 4.4 is out. See INSTALL.md
\ No newline at end of file
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 00000000..9df3d6bf
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,96 @@
+# Integration between Baritone and Impact
+Impact 4.4 has Baritone included.
+
+These instructions apply to Impact 4.3 (and potentially other hacked clients).
+
+To run Baritone on Vanilla, just follow the instructions in the README (it's `./gradlew runClient`).
+
+
+## An Introduction
+There are some basic steps to getting Baritone setup with Impact.
+- Acquiring a build of Baritone
+- Placing Baritone in the libraries directory
+- Modifying the Impact Profile JSON to run baritone
+- How to use Baritone
+
+## Acquiring a build of Baritone
+There are two methods of acquiring a build of Baritone
+
+### Official Release (Not always up to date)
+https://github.com/cabaletta/baritone/releases
+
+For Impact 4.3, there is no Baritone integration yet, so you will want `baritone-standalone-X.Y.Z.jar`.
+
+Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`.
+
+The build is fully deterministic and reproducible, and you can verify Travis did it properly by running `docker build --no-cache -t cabaletta/baritone . && docker run --rm cabaletta/baritone cat /code/dist/checksums.txt` yourself and comparing the shasum. This works identically on Travis, Mac, and Linux (if you have docker on Windows, I'd be grateful if you could let me know if it works there too).
+
+### Building Baritone yourself
+There are a few steps to this
+- Clone this repository
+- Setup the project as instructed in the README
+- Run the ``build`` gradle task. You can either do this using IntelliJ's gradle UI or through a
+command line
+ - Windows: ``gradlew build``
+ - Mac/Linux: ``./gradlew build``
+- The build should be exported into ``/build/libs/baritone-X.Y.Z.jar``
+
+## Placing Baritone in the libraries directory
+``/libraries`` is a neat directory in your Minecraft Installation Directory
+that contains all of the dependencies that are required from the game and some mods. This is where we will be
+putting baritone.
+- Locate the ``libraries`` folder, it should be in the Minecraft Installation Directory
+- Create 3 new subdirectories starting from ``libraries``
+ - ``cabaletta``
+ - ``baritone``
+ - ``X.Y.Z``
+ - Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder
+ - The full path should look like ``/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar``
+
+## Modifying the Impact Profile JSON to run baritone
+The final step is "registering" the Baritone library with Impact, so that it loads on launch.
+- Ensure your Minecraft launcher is closed
+- Navigate back to the Minecraft Installation Directory
+- Find the ``versions`` directory, and open in
+- In here there should be a ``1.12.2-Impact_4.3`` folder.
+ - If you don't have any Impact folder or have a version older than 4.3, you can download Impact here.
+- Open the folder and inside there should be a file called ``1.12.2-Impact_4.3.json``
+- Open the JSON file with a text editor that supports your system's line endings
+ - For example, Notepad on Windows likely will NOT work for this. You should instead use a Text Editor like
+ Notepad++ if you're on Windows. (For other systems, I'm not sure
+ what would work the best so you may have to do some research.)
+- Find the ``libraries`` array in the JSON. It should look something like this.
+ ```
+ "libraries": [
+ {
+ "name": "net.minecraft:launchwrapper:1.12"
+ },
+ {
+ "name": "com.github.ImpactDevelopment:Impact:4.3-1.12.2",
+ "url": "https://impactdevelopment.github.io/maven/"
+ },
+ {
+ "name": "com.github.ImpactDeveloment:ClientAPI:3.0.2",
+ "url": "https://impactdevelopment.github.io/maven/"
+ },
+ ...
+ ```
+- Create two new objects in the array, between the ``Impact`` and ``ClientAPI`` dependencies preferably.
+ ```
+ {
+ "name": "cabaletta:baritone:X.Y.Z"
+ },
+ {
+ "name": "com.github.ImpactDevelopment:SimpleTweaker:1.2",
+ "url": "https://impactdevelopment.github.io/maven/"
+ },
+ ```
+- Now find the ``"minecraftArguments": "..."`` text near the top.
+- At the very end of the quotes where it says ``--tweakClass clientapi.load.ClientTweaker"``, add on the following so it looks like:
+ - ``--tweakClass clientapi.load.ClientTweaker --tweakClass baritone.launch.BaritoneTweakerOptifine"``
+- If you didn't close your launcher for this step, restart it now.
+- You can now launch Impact 4.3 as normal, and Baritone should start up
+
+ ## How to use Baritone
+ Instructions on how to use Baritone are limited, and you may have to read a little bit of code (Really nothing much
+ just plain English), you can view that here.
diff --git a/README.md b/README.md
index ad6980f6..445d34bb 100644
--- a/README.md
+++ b/README.md
@@ -1,46 +1,52 @@
# Baritone
[](https://travis-ci.com/cabaletta/baritone)
+[](https://github.com/cabaletta/baritone/releases)
[](LICENSE)
-[](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade)
+[](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade)
+[](http://hits.dwyl.com/cabaletta/baritone)
+[](https://github.com/cabaletta/baritone/issues)
+[](https://minecraft.gamepedia.com/1.12.2)
-Unofficial Jenkins: [](https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/)
+A Minecraft pathfinder bot.
-A Minecraft pathfinder bot. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/),
+Baritone is the pathfinding system used in [Impact](https://impactdevelopment.github.io/) since 4.4. There's a [showcase video](https://www.youtube.com/watch?v=yI8hgW_m6dQ) made by @Adovin#3153 on Baritone's integration into Impact. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a video I made showing off what it can do.
+
+This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/),
the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths).
Here are some links to help to get started:
- [Features](FEATURES.md)
-- [Baritone + Impact](IMPACT.md)
+- [Installation](INSTALL.md)
There's also some useful information down below
# Setup
-## IntelliJ's Gradle UI
-- Open the project in IntelliJ as a Gradle project
-- Run the Gradle task `setupDecompWorkspace`
-- Run the Gradle task `genIntellijRuns`
-- Refresh the Gradle project (or just restart IntelliJ)
-- Select the "Minecraft Client" launch config and run
-
## Command Line
On Mac OSX and Linux, use `./gradlew` instead of `gradlew`.
Running Baritone:
```
-$ gradlew run
+$ gradlew runClient
```
-Setting up for IntelliJ:
+Building Baritone:
```
-$ gradlew setupDecompWorkspace
-$ gradlew --refresh-dependencies
-$ gradlew genIntellijRuns
+$ gradlew build
```
+For example, to replace out Impact 4.4's Baritone build with a customized one, switch to the `impact4.4-compat` branch, build Baritone as above then copy `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.0.0/baritone-api-1.0.0.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.4/1.12.2-Impact_4.4.json`, find the line `"name": "cabaletta:baritone-api:1.0.0"`, remove the comma from the end, and entirely remove the line that's immediately after (starts with `"url"`).
+
+## IntelliJ's Gradle UI
+- Open the project in IntelliJ as a Gradle project
+- Run the Gradle tasks `setupDecompWorkspace` then `genIntellijRuns`
+- Refresh the Gradle project (or, to be safe, just restart IntelliJ)
+- Select the "Minecraft Client" launch config
+- In `Edit Configurations...` you may need to select `baritone_launch` for `Use classpath of module:`.
+
# Chat control
[Defined Here](src/main/java/baritone/utils/ExampleBaritoneControl.java)
diff --git a/build.gradle b/build.gradle
index 0a1bb804..e0b556a2 100755
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@
*/
group 'baritone'
-version '0.0.3'
+version '1.0.0-hotfix-2'
buildscript {
repositories {
@@ -37,6 +37,10 @@ buildscript {
}
}
+
+import baritone.gradle.task.CreateDistTask
+import baritone.gradle.task.ProguardTask
+
apply plugin: 'java'
apply plugin: 'net.minecraftforge.gradle.tweaker-client'
apply plugin: 'org.spongepowered.mixin'
@@ -54,10 +58,12 @@ sourceSets {
minecraft {
version = '1.12.2'
- mappings = 'snapshot_20180731'
+ mappings = 'stable_39'
tweakClass = 'baritone.launch.BaritoneTweaker'
runDir = 'run'
- makeObfSourceJar = false
+
+ // The sources jar should use SRG names not MCP to ensure compatibility with all mappings
+ makeObfSourceJar = true
}
repositories {
@@ -67,9 +73,15 @@ repositories {
name = 'spongepowered-repo'
url = 'http://repo.spongepowered.org/maven/'
}
+
+ maven {
+ name = 'impactdevelopment-repo'
+ url = 'https://impactdevelopment.github.io/maven/'
+ }
}
dependencies {
+ runtime launchCompile('com.github.ImpactDevelopment:SimpleTweaker:1.2')
runtime launchCompile('org.spongepowered:mixin:0.7.11-SNAPSHOT') {
// Mixin includes a lot of dependencies that are too up-to-date
exclude module: 'launchwrapper'
@@ -88,4 +100,16 @@ mixin {
jar {
from sourceSets.launch.output, sourceSets.api.output
+ preserveFileTimestamps = false
+ reproducibleFileOrder = true
}
+
+task proguard(type: ProguardTask) {
+ url 'https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip'
+ extract 'proguard6.0.3/lib/proguard.jar'
+ versionManifest 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
+}
+
+task createDist(type: CreateDistTask, dependsOn: proguard)
+
+build.finalizedBy(createDist)
diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore
new file mode 100644
index 00000000..daf21d56
--- /dev/null
+++ b/buildSrc/.gitignore
@@ -0,0 +1,3 @@
+build/
+.gradle/
+out/
\ No newline at end of file
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
new file mode 100644
index 00000000..2ac49af0
--- /dev/null
+++ b/buildSrc/build.gradle
@@ -0,0 +1,25 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
+ compile group: 'commons-io', name: 'commons-io', version: '2.6'
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java
new file mode 100644
index 00000000..0450509f
--- /dev/null
+++ b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java
@@ -0,0 +1,102 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.gradle.task;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import org.gradle.api.DefaultTask;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+/**
+ * @author Brady
+ * @since 10/12/2018
+ */
+class BaritoneGradleTask extends DefaultTask {
+
+ protected static final JsonParser PARSER = new JsonParser();
+
+ protected static final String
+ PROGUARD_ZIP = "proguard.zip",
+ PROGUARD_JAR = "proguard.jar",
+ PROGUARD_CONFIG_TEMPLATE = "scripts/proguard.pro",
+ PROGUARD_CONFIG_DEST = "template.pro",
+ PROGUARD_API_CONFIG = "api.pro",
+ PROGUARD_STANDALONE_CONFIG = "standalone.pro",
+ PROGUARD_EXPORT_PATH = "proguard_out.jar",
+
+ VERSION_MANIFEST = "version_manifest.json",
+
+ TEMP_LIBRARY_DIR = "tempLibraries/",
+
+ ARTIFACT_STANDARD = "%s-%s.jar",
+ ARTIFACT_UNOPTIMIZED = "%s-unoptimized-%s.jar",
+ ARTIFACT_API = "%s-api-%s.jar",
+ ARTIFACT_STANDALONE = "%s-standalone-%s.jar";
+
+ protected String artifactName, artifactVersion;
+ protected Path artifactPath, artifactUnoptimizedPath, artifactApiPath, artifactStandalonePath, proguardOut;
+
+ protected void verifyArtifacts() throws IllegalStateException {
+ this.artifactName = getProject().getName();
+ this.artifactVersion = getProject().getVersion().toString();
+
+ this.artifactPath = this.getBuildFile(formatVersion(ARTIFACT_STANDARD));
+ this.artifactUnoptimizedPath = this.getBuildFile(formatVersion(ARTIFACT_UNOPTIMIZED));
+ this.artifactApiPath = this.getBuildFile(formatVersion(ARTIFACT_API));
+ this.artifactStandalonePath = this.getBuildFile(formatVersion(ARTIFACT_STANDALONE));
+
+ this.proguardOut = this.getTemporaryFile(PROGUARD_EXPORT_PATH);
+
+ if (!Files.exists(this.artifactPath)) {
+ throw new IllegalStateException("Artifact not found! Run build first!");
+ }
+ }
+
+ protected void write(InputStream stream, Path file) throws Exception {
+ if (Files.exists(file)) {
+ Files.delete(file);
+ }
+ Files.copy(stream, file);
+ }
+
+ protected String formatVersion(String string) {
+ return String.format(string, this.artifactName, this.artifactVersion);
+ }
+
+ protected Path getRelativeFile(String file) {
+ return Paths.get(new File(file).getAbsolutePath());
+ }
+
+ protected Path getTemporaryFile(String file) {
+ return Paths.get(new File(getTemporaryDir(), file).getAbsolutePath());
+ }
+
+ protected Path getBuildFile(String file) {
+ return getRelativeFile("build/libs/" + file);
+ }
+
+ protected JsonElement readJson(List lines) {
+ return PARSER.parse(String.join("\n", lines));
+ }
+}
diff --git a/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java b/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java
new file mode 100644
index 00000000..49e2e142
--- /dev/null
+++ b/buildSrc/src/main/java/baritone/gradle/task/CreateDistTask.java
@@ -0,0 +1,82 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.gradle.task;
+
+import org.gradle.api.tasks.TaskAction;
+
+import javax.xml.bind.DatatypeConverter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
+/**
+ * @author Brady
+ * @since 10/12/2018
+ */
+public class CreateDistTask extends BaritoneGradleTask {
+
+ private static MessageDigest SHA1_DIGEST;
+
+ @TaskAction
+ protected void exec() throws Exception {
+ super.verifyArtifacts();
+
+ // Define the distribution file paths
+ Path api = getRelativeFile("dist/" + formatVersion(ARTIFACT_API));
+ Path standalone = getRelativeFile("dist/" + formatVersion(ARTIFACT_STANDALONE));
+ Path unoptimized = getRelativeFile("dist/" + formatVersion(ARTIFACT_UNOPTIMIZED));
+
+ // NIO will not automatically create directories
+ Path dir = getRelativeFile("dist/");
+ if (!Files.exists(dir)) {
+ Files.createDirectory(dir);
+ }
+
+ // Copy build jars to dist/
+ Files.copy(this.artifactApiPath, api, REPLACE_EXISTING);
+ Files.copy(this.artifactStandalonePath, standalone, REPLACE_EXISTING);
+ Files.copy(this.artifactUnoptimizedPath, unoptimized, REPLACE_EXISTING);
+
+ // Calculate all checksums and format them like "shasum"
+ List shasum = Stream.of(api, standalone, unoptimized)
+ .map(path -> sha1(path) + " " + path.getFileName().toString())
+ .collect(Collectors.toList());
+
+ shasum.forEach(System.out::println);
+
+ // Write the checksums to a file
+ Files.write(getRelativeFile("dist/checksums.txt"), shasum);
+ }
+
+ private static synchronized String sha1(Path path) {
+ try {
+ if (SHA1_DIGEST == null) {
+ SHA1_DIGEST = MessageDigest.getInstance("SHA-1");
+ }
+ return DatatypeConverter.printHexBinary(SHA1_DIGEST.digest(Files.readAllBytes(path))).toLowerCase();
+ } catch (Exception e) {
+ // haha no thanks
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java
new file mode 100644
index 00000000..350f7446
--- /dev/null
+++ b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java
@@ -0,0 +1,260 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.gradle.task;
+
+import baritone.gradle.util.Determinizer;
+import com.google.gson.*;
+import org.apache.commons.io.IOUtils;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.TaskAction;
+import org.gradle.internal.Pair;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
+/**
+ * @author Brady
+ * @since 10/11/2018
+ */
+public class ProguardTask extends BaritoneGradleTask {
+
+ private static final Pattern TEMP_LIBRARY_PATTERN = Pattern.compile("-libraryjars 'tempLibraries\\/([a-zA-Z0-9/_\\-\\.]+)\\.jar'");
+
+ @Input
+ private String url;
+
+ @Input
+ private String extract;
+
+ @Input
+ private String versionManifest;
+
+ private Map versionDownloadMap;
+ private List requiredLibraries;
+
+ @TaskAction
+ protected void exec() throws Exception {
+ super.verifyArtifacts();
+
+ // "Haha brady why don't you make separate tasks"
+ processArtifact();
+ downloadProguard();
+ extractProguard();
+ generateConfigs();
+ downloadVersionManifest();
+ acquireDependencies();
+ proguardApi();
+ proguardStandalone();
+ cleanup();
+ }
+
+ private void processArtifact() throws Exception {
+ if (Files.exists(this.artifactUnoptimizedPath)) {
+ Files.delete(this.artifactUnoptimizedPath);
+ }
+
+ Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString());
+ }
+
+ private void downloadProguard() throws Exception {
+ Path proguardZip = getTemporaryFile(PROGUARD_ZIP);
+ if (!Files.exists(proguardZip)) {
+ write(new URL(this.url).openStream(), proguardZip);
+ }
+ }
+
+ private void extractProguard() throws Exception {
+ Path proguardJar = getTemporaryFile(PROGUARD_JAR);
+ if (!Files.exists(proguardJar)) {
+ ZipFile zipFile = new ZipFile(getTemporaryFile(PROGUARD_ZIP).toFile());
+ ZipEntry zipJarEntry = zipFile.getEntry(this.extract);
+ write(zipFile.getInputStream(zipJarEntry), proguardJar);
+ zipFile.close();
+ }
+ }
+
+ private void generateConfigs() throws Exception {
+ Files.copy(getRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), REPLACE_EXISTING);
+
+ // Setup the template that will be used to derive the API and Standalone configs
+ List template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST));
+ template.add(0, "-injars " + this.artifactPath.toString());
+ template.add(1, "-outjars " + this.getTemporaryFile(PROGUARD_EXPORT_PATH));
+
+ // Acquire the RT jar using "java -verbose". This doesn't work on Java 9+
+ Process p = new ProcessBuilder("java", "-verbose").start();
+ String out = IOUtils.toString(p.getInputStream(), "UTF-8").split("\n")[0].split("Opened ")[1].replace("]", "");
+ template.add(2, "-libraryjars '" + out + "'");
+
+ // API config doesn't require any changes from the changes that we made to the template
+ Files.write(getTemporaryFile(PROGUARD_API_CONFIG), template);
+
+ // For the Standalone config, don't keep the API package
+ List standalone = new ArrayList<>(template);
+ standalone.removeIf(s -> s.contains("# this is the keep api"));
+ Files.write(getTemporaryFile(PROGUARD_STANDALONE_CONFIG), standalone);
+
+ // Discover all of the libraries that we will need to acquire from gradle
+ this.requiredLibraries = new ArrayList<>();
+ template.forEach(line -> {
+ if (!line.startsWith("#")) {
+ Matcher m = TEMP_LIBRARY_PATTERN.matcher(line);
+ if (m.find()) {
+ this.requiredLibraries.add(m.group(1));
+ }
+ }
+ });
+ }
+
+ private void downloadVersionManifest() throws Exception {
+ Path manifestJson = getTemporaryFile(VERSION_MANIFEST);
+ write(new URL(this.versionManifest).openStream(), manifestJson);
+
+ // Place all the versions in the map with their download URL
+ this.versionDownloadMap = new HashMap<>();
+ JsonObject json = readJson(Files.readAllLines(manifestJson)).getAsJsonObject();
+ JsonArray versions = json.getAsJsonArray("versions");
+ versions.forEach(element -> {
+ JsonObject object = element.getAsJsonObject();
+ this.versionDownloadMap.put(object.get("id").getAsString(), object.get("url").getAsString());
+ });
+ }
+
+ private void acquireDependencies() throws Exception {
+
+ // Create a map of all of the dependencies that we are able to access in this project
+ // Likely a better way to do this, I just pair the dependency with the first valid configuration
+ Map> dependencyLookupMap = new HashMap<>();
+ getProject().getConfigurations().stream().filter(Configuration::isCanBeResolved).forEach(config ->
+ config.getAllDependencies().forEach(dependency ->
+ dependencyLookupMap.putIfAbsent(dependency.getName() + "-" + dependency.getVersion(), Pair.of(config, dependency))));
+
+ // Create the directory if it doesn't already exist
+ Path tempLibraries = getTemporaryFile(TEMP_LIBRARY_DIR);
+ if (!Files.exists(tempLibraries)) {
+ Files.createDirectory(tempLibraries);
+ }
+
+ // Iterate the required libraries to copy them to tempLibraries
+ for (String lib : this.requiredLibraries) {
+ // Download the version jar from the URL acquired from the version manifest
+ if (lib.startsWith("minecraft")) {
+ String version = lib.split("-")[1];
+ Path versionJar = getTemporaryFile("tempLibraries/" + lib + ".jar");
+ if (!Files.exists(versionJar)) {
+ JsonObject versionJson = PARSER.parse(new InputStreamReader(new URL(this.versionDownloadMap.get(version)).openStream())).getAsJsonObject();
+ String url = versionJson.getAsJsonObject("downloads").getAsJsonObject("client").getAsJsonPrimitive("url").getAsString();
+ write(new URL(url).openStream(), versionJar);
+ }
+ continue;
+ }
+
+ // Find a configuration/dependency pair that matches the desired library
+ Pair pair = null;
+ for (Map.Entry> entry : dependencyLookupMap.entrySet()) {
+ if (entry.getKey().startsWith(lib)) {
+ pair = entry.getValue();
+ }
+ }
+
+ // The pair must be non-null
+ Objects.requireNonNull(pair);
+
+ // Find the library jar file, and copy it to tempLibraries
+ for (File file : pair.getLeft().files(pair.getRight())) {
+ if (file.getName().startsWith(lib)) {
+ Files.copy(file.toPath(), getTemporaryFile("tempLibraries/" + lib + ".jar"), REPLACE_EXISTING);
+ }
+ }
+ }
+ }
+
+ private void proguardApi() throws Exception {
+ runProguard(getTemporaryFile(PROGUARD_API_CONFIG));
+ Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString());
+ }
+
+ private void proguardStandalone() throws Exception {
+ runProguard(getTemporaryFile(PROGUARD_STANDALONE_CONFIG));
+ Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString());
+ }
+
+ private void cleanup() {
+ try {
+ Files.delete(this.proguardOut);
+ } catch (IOException ignored) {}
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setExtract(String extract) {
+ this.extract = extract;
+ }
+
+ public void setVersionManifest(String versionManifest) {
+ this.versionManifest = versionManifest;
+ }
+
+ private void runProguard(Path config) throws Exception {
+ // Delete the existing proguard output file. Proguard probably handles this already, but why not do it ourselves
+ if (Files.exists(this.proguardOut)) {
+ Files.delete(this.proguardOut);
+ }
+
+ Path proguardJar = getTemporaryFile(PROGUARD_JAR);
+ Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString())
+ .directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder]
+ .start();
+
+ // We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this
+ this.printOutputLog(p.getInputStream());
+ this.printOutputLog(p.getErrorStream());
+
+ // Halt the current thread until the process is complete, if the exit code isn't 0, throw an exception
+ int exitCode = p.waitFor();
+ if (exitCode != 0) {
+ throw new IllegalStateException("Proguard exited with code " + exitCode);
+ }
+ }
+
+ private void printOutputLog(InputStream stream) {
+ new Thread(() -> {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ System.out.println(line);
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+}
diff --git a/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java b/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java
new file mode 100644
index 00000000..fc268cd3
--- /dev/null
+++ b/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java
@@ -0,0 +1,143 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.gradle.util;
+
+import com.google.gson.*;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.stream.Collectors;
+
+/**
+ * Make a .jar file deterministic by sorting all entries by name, and setting all the last modified times to 42069.
+ * This makes the build 100% reproducible since the timestamp when you built it no longer affects the final file.
+ *
+ * @author leijurv
+ */
+public class Determinizer {
+
+ public static void determinize(String inputPath, String outputPath) throws IOException {
+ System.out.println("Running Determinizer");
+ System.out.println(" Input path: " + inputPath);
+ System.out.println(" Output path: " + outputPath);
+
+ try (
+ JarFile jarFile = new JarFile(new File(inputPath));
+ JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File(outputPath)))
+ ) {
+
+ List entries = jarFile.stream()
+ .sorted(Comparator.comparing(JarEntry::getName))
+ .collect(Collectors.toList());
+
+ for (JarEntry entry : entries) {
+ if (entry.getName().equals("META-INF/fml_cache_annotation.json")) {
+ continue;
+ }
+ if (entry.getName().equals("META-INF/fml_cache_class_versions.json")) {
+ continue;
+ }
+ JarEntry clone = new JarEntry(entry.getName());
+ clone.setTime(42069);
+ jos.putNextEntry(clone);
+ if (entry.getName().endsWith(".refmap.json")) {
+ JsonObject object = new JsonParser().parse(new InputStreamReader(jarFile.getInputStream(entry))).getAsJsonObject();
+ jos.write(writeSorted(object).getBytes());
+ } else {
+ copy(jarFile.getInputStream(entry), jos);
+ }
+ }
+ jos.finish();
+ }
+ }
+
+ private static void copy(InputStream is, OutputStream os) throws IOException {
+ byte[] buffer = new byte[1024];
+ int len;
+ while ((len = is.read(buffer)) != -1) {
+ os.write(buffer, 0, len);
+ }
+ }
+
+ private static String writeSorted(JsonObject in) throws IOException {
+ StringWriter writer = new StringWriter();
+ JsonWriter jw = new JsonWriter(writer);
+ ORDERED_JSON_WRITER.write(jw, in);
+ return writer.toString() + "\n";
+ }
+
+ /**
+ * All credits go to GSON and its contributors. GSON is licensed under the Apache 2.0 License.
+ * This implementation has been modified to write {@link JsonObject} keys in order.
+ *
+ * @see GSON License
+ * @see Original Source
+ */
+ private static final TypeAdapter ORDERED_JSON_WRITER = new TypeAdapter() {
+
+ @Override
+ public JsonElement read(JsonReader in) {
+ return null;
+ }
+
+ @Override
+ public void write(JsonWriter out, JsonElement value) throws IOException {
+ if (value == null || value.isJsonNull()) {
+ out.nullValue();
+ } else if (value.isJsonPrimitive()) {
+ JsonPrimitive primitive = value.getAsJsonPrimitive();
+ if (primitive.isNumber()) {
+ out.value(primitive.getAsNumber());
+ } else if (primitive.isBoolean()) {
+ out.value(primitive.getAsBoolean());
+ } else {
+ out.value(primitive.getAsString());
+ }
+
+ } else if (value.isJsonArray()) {
+ out.beginArray();
+ for (JsonElement e : value.getAsJsonArray()) {
+ write(out, e);
+ }
+ out.endArray();
+
+ } else if (value.isJsonObject()) {
+ out.beginObject();
+
+ List> entries = new ArrayList<>(value.getAsJsonObject().entrySet());
+ entries.sort(Comparator.comparing(Map.Entry::getKey));
+ for (Map.Entry e : entries) {
+ out.name(e.getKey());
+ write(out, e.getValue());
+ }
+ out.endObject();
+
+ } else {
+ throw new IllegalArgumentException("Couldn't write " + value.getClass());
+ }
+ }
+ };
+}
diff --git a/scripts/build.sh b/scripts/build.sh
deleted file mode 100644
index a224a884..00000000
--- a/scripts/build.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-set -e # this makes the whole script fail immediately if any one of these commands fails
-./gradlew build
-export VERSION=$(cat build.gradle | grep "version '" | cut -d "'" -f 2-2)
-
-wget -nv https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip
-unzip proguard6.0.3.zip 2>&1 > /dev/null
-cd build/libs
-echo "-injars 'baritone-$VERSION.jar'" >> api.pro # insert current version
-cat ../../scripts/proguard.pro | grep -v "this is the rt jar" | grep -v "\-injars" >> api.pro # remove default rt jar and injar lines
-echo "-libraryjars '$(java -verbose 2>/dev/null | sed -ne '1 s/\[Opened \(.*\)\]/\1/p')'" >> api.pro # insert correct rt.jar location
-tail api.pro # debug, print out what the previous two commands generated
-cat api.pro | grep -v "\-keep class baritone.api" > standalone.pro # standalone doesn't keep baritone api
-
-#wget -nv https://www.dropbox.com/s/zmc2l3jnwdvzvak/tempLibraries.zip?dl=1 # i'm sorry
-#mv tempLibraries.zip?dl=1 tempLibraries.zip
-#unzip tempLibraries.zip
-
-#instead of downloading these jars from my dropbox in a zip, just assume gradle's already got them for us
-mkdir -p tempLibraries
-cat ../../scripts/proguard.pro | grep tempLibraries | grep .jar | cut -d "/" -f 2- | cut -d "'" -f -1 | xargs -n1 -I{} bash -c "find ~/.gradle -name {}" | tee /dev/stderr | xargs -n1 -I{} cp {} tempLibraries
-
-mkdir ../../dist
-java -jar ../../proguard6.0.3/lib/proguard.jar @api.pro
-mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-api-$VERSION.jar
-java -jar ../../proguard6.0.3/lib/proguard.jar @standalone.pro
-mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-standalone-$VERSION.jar
-mv baritone-$VERSION.jar ../../dist/baritone-unoptimized-$VERSION.jar
-cd ../../dist
-shasum * | tee checksums.txt
-cd ..
\ No newline at end of file
diff --git a/scripts/proguard.pro b/scripts/proguard.pro
index 28120808..a13a0e3f 100644
--- a/scripts/proguard.pro
+++ b/scripts/proguard.pro
@@ -1,7 +1,3 @@
--injars baritone-0.0.3.jar
--outjars Obfuscated
-
-
-keepattributes Signature
-keepattributes *Annotation*
@@ -16,10 +12,14 @@
-flattenpackagehierarchy
-repackageclasses 'baritone'
-#-keep class baritone.behavior.** { *; }
--keep class baritone.api.** { *; }
-#-keep class baritone.* { *; }
-#-keep class baritone.pathing.goals.** { *; }
+-keep class baritone.api.** { *; } # this is the keep api
+
+# service provider needs these class names
+-keep class baritone.BaritoneProvider
+-keep class baritone.api.IBaritoneProvider
+
+# hack
+-keep class baritone.utils.ExampleBaritoneControl { *; }
# setting names are reflected from field names, so keep field names
-keepclassmembers class baritone.api.Settings {
@@ -30,10 +30,11 @@
-keep class baritone.launch.** { *; }
# copy all necessary libraries into tempLibraries to build
--libraryjars '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/rt.jar' # this is the rt jar
-libraryjars 'tempLibraries/minecraft-1.12.2.jar'
+-libraryjars 'tempLibraries/SimpleTweaker-1.2.jar'
+
-libraryjars 'tempLibraries/authlib-1.5.25.jar'
-libraryjars 'tempLibraries/codecjorbis-20101023.jar'
-libraryjars 'tempLibraries/codecwav-20101023.jar'
@@ -48,7 +49,6 @@
-libraryjars 'tempLibraries/httpclient-4.3.3.jar'
-libraryjars 'tempLibraries/httpcore-4.3.2.jar'
-libraryjars 'tempLibraries/icu4j-core-mojang-51.2.jar'
--libraryjars 'tempLibraries/java-objc-bridge-1.0.0.jar'
-libraryjars 'tempLibraries/jinput-2.0.5.jar'
-libraryjars 'tempLibraries/jna-4.4.0.jar'
-libraryjars 'tempLibraries/jopt-simple-5.0.3.jar'
@@ -58,8 +58,12 @@
-libraryjars 'tempLibraries/librarylwjglopenal-20100824.jar'
-libraryjars 'tempLibraries/log4j-api-2.8.1.jar'
-libraryjars 'tempLibraries/log4j-core-2.8.1.jar'
--libraryjars 'tempLibraries/lwjgl-2.9.4-nightly-20150209.jar'
--libraryjars 'tempLibraries/lwjgl_util-2.9.4-nightly-20150209.jar'
+
+# startsWith is used to check the library, and mac/linux differ in which version they use
+# this is FINE
+-libraryjars 'tempLibraries/lwjgl-.jar'
+-libraryjars 'tempLibraries/lwjgl_util-.jar'
+
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
-libraryjars 'tempLibraries/oshi-core-1.1.jar'
-libraryjars 'tempLibraries/patchy-1.1.jar'
diff --git a/src/api/java/baritone/api/BaritoneAPI.java b/src/api/java/baritone/api/BaritoneAPI.java
index aa9491db..b9dbcd04 100644
--- a/src/api/java/baritone/api/BaritoneAPI.java
+++ b/src/api/java/baritone/api/BaritoneAPI.java
@@ -17,8 +17,20 @@
package baritone.api;
-import baritone.api.behavior.*;
+import baritone.api.behavior.ILookBehavior;
+import baritone.api.behavior.IMemoryBehavior;
+import baritone.api.behavior.IPathingBehavior;
import baritone.api.cache.IWorldProvider;
+import baritone.api.cache.IWorldScanner;
+import baritone.api.event.listener.IGameEventListener;
+import baritone.api.process.ICustomGoalProcess;
+import baritone.api.process.IFollowProcess;
+import baritone.api.process.IGetToBlockProcess;
+import baritone.api.process.IMineProcess;
+import baritone.api.utils.SettingsUtil;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
/**
* API exposure for various things implemented in Baritone.
@@ -28,37 +40,38 @@ import baritone.api.cache.IWorldProvider;
* @author Brady
* @since 9/23/2018
*/
-public class BaritoneAPI {
+public final class BaritoneAPI {
- // General
- private static final Settings settings = new Settings();
- private static IWorldProvider worldProvider;
+ private static final IBaritone baritone;
+ private static final Settings settings;
- // Behaviors
- private static IFollowBehavior followBehavior;
- private static ILookBehavior lookBehavior;
- private static IMemoryBehavior memoryBehavior;
- private static IMineBehavior mineBehavior;
- private static IPathingBehavior pathingBehavior;
+ static {
+ ServiceLoader baritoneLoader = ServiceLoader.load(IBaritoneProvider.class);
+ Iterator instances = baritoneLoader.iterator();
+ baritone = instances.next().getBaritoneForPlayer(null); // PWNAGE
- public static IFollowBehavior getFollowBehavior() {
- return followBehavior;
+ settings = new Settings();
+ SettingsUtil.readAndApply(settings);
+ }
+
+ public static IFollowProcess getFollowProcess() {
+ return baritone.getFollowProcess();
}
public static ILookBehavior getLookBehavior() {
- return lookBehavior;
+ return baritone.getLookBehavior();
}
public static IMemoryBehavior getMemoryBehavior() {
- return memoryBehavior;
+ return baritone.getMemoryBehavior();
}
- public static IMineBehavior getMineBehavior() {
- return mineBehavior;
+ public static IMineProcess getMineProcess() {
+ return baritone.getMineProcess();
}
public static IPathingBehavior getPathingBehavior() {
- return pathingBehavior;
+ return baritone.getPathingBehavior();
}
public static Settings getSettings() {
@@ -66,34 +79,22 @@ public class BaritoneAPI {
}
public static IWorldProvider getWorldProvider() {
- return worldProvider;
+ return baritone.getWorldProvider();
}
- /**
- * FOR INTERNAL USE ONLY
- */
- public static void registerProviders(
- IWorldProvider worldProvider
- ) {
- BaritoneAPI.worldProvider = worldProvider;
+ public static IWorldScanner getWorldScanner() {
+ return baritone.getWorldScanner();
}
- /**
- * 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;
+ public static ICustomGoalProcess getCustomGoalProcess() {
+ return baritone.getCustomGoalProcess();
+ }
+
+ public static IGetToBlockProcess getGetToBlockProcess() {
+ return baritone.getGetToBlockProcess();
+ }
+
+ public static void registerEventListener(IGameEventListener listener) {
+ baritone.registerEventListener(listener);
}
- // @formatter:on
}
diff --git a/src/api/java/baritone/api/IBaritone.java b/src/api/java/baritone/api/IBaritone.java
new file mode 100644
index 00000000..aee9dead
--- /dev/null
+++ b/src/api/java/baritone/api/IBaritone.java
@@ -0,0 +1,89 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api;
+
+import baritone.api.behavior.ILookBehavior;
+import baritone.api.behavior.IMemoryBehavior;
+import baritone.api.behavior.IPathingBehavior;
+import baritone.api.cache.IWorldProvider;
+import baritone.api.cache.IWorldScanner;
+import baritone.api.event.listener.IGameEventListener;
+import baritone.api.process.ICustomGoalProcess;
+import baritone.api.process.IFollowProcess;
+import baritone.api.process.IGetToBlockProcess;
+import baritone.api.process.IMineProcess;
+
+/**
+ * @author Brady
+ * @since 9/29/2018
+ */
+public interface IBaritone {
+
+ /**
+ * @return The {@link IFollowProcess} instance
+ * @see IFollowProcess
+ */
+ IFollowProcess getFollowProcess();
+
+ /**
+ * @return The {@link ILookBehavior} instance
+ * @see ILookBehavior
+ */
+ ILookBehavior getLookBehavior();
+
+ /**
+ * @return The {@link IMemoryBehavior} instance
+ * @see IMemoryBehavior
+ */
+ IMemoryBehavior getMemoryBehavior();
+
+ /**
+ * @return The {@link IMineProcess} instance
+ * @see IMineProcess
+ */
+ IMineProcess getMineProcess();
+
+ /**
+ * @return The {@link IPathingBehavior} instance
+ * @see IPathingBehavior
+ */
+ IPathingBehavior getPathingBehavior();
+
+ /**
+ * @return The {@link IWorldProvider} instance
+ * @see IWorldProvider
+ */
+ IWorldProvider getWorldProvider();
+
+ /**
+ * @return The {@link IWorldScanner} instance
+ * @see IWorldScanner
+ */
+ IWorldScanner getWorldScanner();
+
+ ICustomGoalProcess getCustomGoalProcess();
+
+ IGetToBlockProcess getGetToBlockProcess();
+
+ /**
+ * Registers a {@link IGameEventListener} with Baritone's "event bus".
+ *
+ * @param listener The listener
+ */
+ void registerEventListener(IGameEventListener listener);
+}
diff --git a/src/api/java/baritone/api/IBaritoneProvider.java b/src/api/java/baritone/api/IBaritoneProvider.java
new file mode 100644
index 00000000..745842ce
--- /dev/null
+++ b/src/api/java/baritone/api/IBaritoneProvider.java
@@ -0,0 +1,35 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api;
+
+import net.minecraft.client.entity.EntityPlayerSP;
+
+/**
+ * @author Leijurv
+ */
+public interface IBaritoneProvider {
+
+ /**
+ * Provides the {@link IBaritone} instance for a given {@link EntityPlayerSP}. This will likely be
+ * replaced with {@code #getBaritoneForUser(IBaritoneUser)} when {@code bot-system} is merged.
+ *
+ * @param player The player
+ * @return The {@link IBaritone} instance.
+ */
+ IBaritone getBaritoneForPlayer(EntityPlayerSP player);
+}
diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java
index fdbaaf45..7fce0254 100644
--- a/src/api/java/baritone/api/Settings.java
+++ b/src/api/java/baritone/api/Settings.java
@@ -56,6 +56,13 @@ public class Settings {
*/
public Setting blockPlacementPenalty = new Setting<>(20D);
+ /**
+ * This is just a tiebreaker to make it less likely to break blocks if it can avoid it.
+ * For example, fire has a break cost of 0, this makes it nonzero, so all else being equal
+ * it will take an otherwise equivalent route that doesn't require it to put out fire.
+ */
+ public Setting blockBreakAdditionalPenalty = new Setting<>(2D);
+
/**
* Allow Baritone to fall arbitrary distances and place a water bucket beneath it.
* Reliability: questionable.
@@ -149,7 +156,7 @@ public class Settings {
*
* @see Issue #18
*/
- public Setting backtrackCostFavoringCoefficient = new Setting<>(0.9);
+ public Setting backtrackCostFavoringCoefficient = new Setting<>(0.5);
/**
* Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies,
@@ -191,7 +198,7 @@ public class Settings {
/**
* Start planning the next path once the remaining movements tick estimates sum up to less than this value
*/
- public Setting planningTickLookAhead = new Setting<>(100);
+ public Setting planningTickLookAhead = new Setting<>(150);
/**
* Default size of the Long2ObjectOpenHashMap used in pathing
@@ -269,6 +276,13 @@ public class Settings {
*/
public Setting chunkCaching = new Setting<>(true);
+ /**
+ * On save, delete from RAM any cached regions that are more than 1024 blocks away from the player
+ *
+ * Temporarily disabled, see issue #248
+ */
+ public Setting pruneRegionsFromRAM = new Setting<>(false);
+
/**
* Print all the debug messages to chat
*/
@@ -295,6 +309,21 @@ public class Settings {
*/
public Setting renderGoal = new Setting<>(true);
+ /**
+ * Ignore depth when rendering the goal
+ */
+ public Setting renderGoalIgnoreDepth = new Setting<>(true);
+
+ /**
+ * Ignore depth when rendering the selection boxes (to break, to place, to walk into)
+ */
+ public Setting renderSelectionBoxesIgnoreDepth = new Setting<>(true);
+
+ /**
+ * Ignore depth when rendering the path
+ */
+ public Setting renderPathIgnoreDepth = new Setting<>(true);
+
/**
* Line width of the path when rendered, in pixels
*/
@@ -348,12 +377,27 @@ public class Settings {
*/
public Setting walkWhileBreaking = new Setting<>(true);
+ /**
+ * If we are more than 500 movements into the current path, discard the oldest segments, as they are no longer useful
+ */
+ public Setting maxPathHistoryLength = new Setting<>(300);
+
+ /**
+ * If the current path is too long, cut off this many movements from the beginning.
+ */
+ public Setting pathHistoryCutoffAmount = new Setting<>(50);
+
/**
* Rescan for the goal once every 5 ticks.
* Set to 0 to disable.
*/
public Setting mineGoalUpdateInterval = new Setting<>(5);
+ /**
+ * While mining, should it also consider dropped items of the correct type as a pathing destination (as well as ore blocks)?
+ */
+ public Setting mineScanDroppedItems = new Setting<>(true);
+
/**
* Cancel the current path if the goal has changed, and the path originally ended in the goal but doesn't anymore.
*
@@ -374,6 +418,18 @@ public class Settings {
*/
public Setting axisHeight = new Setting<>(120);
+ /**
+ * Allow MineBehavior to use X-Ray to see where the ores are. Turn this option off to force it to mine "legit"
+ * where it will only mine an ore once it can actually see it, so it won't do or know anything that a normal player
+ * couldn't. If you don't want it to look like you're X-Raying, turn this off
+ */
+ public Setting legitMine = new Setting<>(false);
+
+ /**
+ * What Y level to go to for legit strip mining
+ */
+ public Setting legitMineYLevel = new Setting<>(11);
+
/**
* When mining block of a certain type, try to mine two at once instead of one.
* If the block above is also a goal block, set GoalBlock instead of GoalTwoBlocks
@@ -404,6 +460,28 @@ public class Settings {
*/
public Setting followRadius = new Setting<>(3);
+ /**
+ * Cached chunks (regardless of if they're in RAM or saved to disk) expire and are deleted after this number of seconds
+ * -1 to disable
+ *
+ * I would highly suggest leaving this setting disabled (-1).
+ *
+ * The only valid reason I can think of enable this setting is if you are extremely low on disk space and you play on multiplayer,
+ * and can't take (average) 300kb saved for every 512x512 area. (note that more complicated terrain is less compressible and will take more space)
+ *
+ * However, simply discarding old chunks because they are old is inadvisable. Baritone is extremely good at correcting
+ * itself and its paths as it learns new information, as new chunks load. There is no scenario in which having an
+ * incorrect cache can cause Baritone to get stuck, take damage, or perform any action it wouldn't otherwise, everything
+ * is rechecked once the real chunk is in range.
+ *
+ * Having a robust cache greatly improves long distance pathfinding, as it's able to go around large scale obstacles
+ * before they're in render distance. In fact, when the chunkCaching setting is disabled and Baritone starts anew
+ * every time, or when you enter a completely new and very complicated area, it backtracks far more often because it
+ * has to build up that cache from scratch. But after it's gone through an area just once, the next time will have zero
+ * backtracking, since the entire area is now known and cached.
+ */
+ public Setting cachedChunksExpirySeconds = new Setting<>(-1L);
+
/**
* 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
@@ -451,11 +529,19 @@ public class Settings {
*/
public Setting colorGoalBox = new Setting<>(Color.GREEN);
+ /**
+ * A map of lowercase setting field names to their respective setting
+ */
public final Map> byLowerName;
+
+ /**
+ * A list of all settings
+ */
public final List> allSettings;
public class Setting {
public T value;
+ public final T defaultValue;
private String name;
private final Class klass;
@@ -465,6 +551,7 @@ public class Settings {
throw new IllegalArgumentException("Cannot determine value type class from null");
}
this.value = value;
+ this.defaultValue = value;
this.klass = (Class) value.getClass();
}
@@ -488,7 +575,7 @@ public class Settings {
// here be dragons
- {
+ Settings() {
Field[] temp = getClass().getFields();
HashMap> tmpByName = new HashMap<>();
List> tmpAll = new ArrayList<>();
@@ -523,6 +610,4 @@ public class Settings {
}
return result;
}
-
- Settings() { }
}
diff --git a/src/api/java/baritone/api/behavior/IBehavior.java b/src/api/java/baritone/api/behavior/IBehavior.java
index aee144e2..248148e7 100644
--- a/src/api/java/baritone/api/behavior/IBehavior.java
+++ b/src/api/java/baritone/api/behavior/IBehavior.java
@@ -18,10 +18,9 @@
package baritone.api.behavior;
import baritone.api.event.listener.AbstractGameEventListener;
-import baritone.api.utils.interfaces.Toggleable;
/**
* @author Brady
* @since 9/23/2018
*/
-public interface IBehavior extends AbstractGameEventListener, Toggleable {}
+public interface IBehavior extends AbstractGameEventListener {}
diff --git a/src/api/java/baritone/api/behavior/ILookBehavior.java b/src/api/java/baritone/api/behavior/ILookBehavior.java
index b5b5d63b..058a5dd8 100644
--- a/src/api/java/baritone/api/behavior/ILookBehavior.java
+++ b/src/api/java/baritone/api/behavior/ILookBehavior.java
@@ -33,7 +33,7 @@ public interface ILookBehavior extends IBehavior {
* otherwise, it should be {@code false};
*
* @param rotation The target rotations
- * @param force Whether or not to "force" the rotations
+ * @param force Whether or not to "force" the rotations
*/
void updateTarget(Rotation rotation, boolean force);
}
diff --git a/src/api/java/baritone/api/behavior/IMemoryBehavior.java b/src/api/java/baritone/api/behavior/IMemoryBehavior.java
index ea5e9007..6b6df1dd 100644
--- a/src/api/java/baritone/api/behavior/IMemoryBehavior.java
+++ b/src/api/java/baritone/api/behavior/IMemoryBehavior.java
@@ -20,6 +20,8 @@ package baritone.api.behavior;
import baritone.api.behavior.memory.IRememberedInventory;
import net.minecraft.util.math.BlockPos;
+import java.util.Map;
+
/**
* @author Brady
* @since 9/23/2018
@@ -33,4 +35,11 @@ public interface IMemoryBehavior extends IBehavior {
* @return The remembered inventory
*/
IRememberedInventory getInventoryByPos(BlockPos pos);
+
+ /**
+ * Gets the map of all block positions to their remembered inventories.
+ *
+ * @return Map of block positions to their respective remembered inventories
+ */
+ Map getRememberedInventories();
}
diff --git a/src/api/java/baritone/api/behavior/IPathingBehavior.java b/src/api/java/baritone/api/behavior/IPathingBehavior.java
index e21d999d..e9ebe405 100644
--- a/src/api/java/baritone/api/behavior/IPathingBehavior.java
+++ b/src/api/java/baritone/api/behavior/IPathingBehavior.java
@@ -17,7 +17,10 @@
package baritone.api.behavior;
+import baritone.api.pathing.calc.IPath;
+import baritone.api.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.Goal;
+import baritone.api.pathing.path.IPathExecutor;
import java.util.Optional;
@@ -36,33 +39,49 @@ public interface IPathingBehavior extends IBehavior {
*/
Optional ticksRemainingInSegment();
- /**
- * Sets the pathing goal.
- *
- * @param goal The pathing goal
- */
- void setGoal(Goal goal);
-
/**
* @return The current pathing goal
*/
Goal getGoal();
- /**
- * Begins pathing. Calculation will start in a new thread, and once completed,
- * movement will commence. Returns whether or not the operation was successful.
- *
- * @return Whether or not the operation was successful
- */
- boolean path();
-
/**
* @return Whether or not a path is currently being executed.
*/
boolean isPathing();
/**
- * Cancels the pathing behavior or the current path calculation.
+ * Cancels the pathing behavior or the current path calculation, and all processes that could be controlling path.
+ *
+ * Basically, "MAKE IT STOP".
+ *
+ * @return Whether or not the pathing behavior was canceled. All processes are guaranteed to be canceled, but the
+ * PathingBehavior might be in the middle of an uncancelable action like a parkour jump
*/
- void cancel();
+ boolean cancelEverything();
+
+ /**
+ * Returns the current path, from the current path executor, if there is one.
+ *
+ * @return The current path
+ */
+ default Optional getPath() {
+ return Optional.ofNullable(getCurrent()).map(IPathExecutor::getPath);
+ }
+
+ /**
+ * @return The current path finder being executed
+ */
+ Optional getPathFinder();
+
+ /**
+ * @return The current path executor
+ */
+ IPathExecutor getCurrent();
+
+ /**
+ * Returns the next path executor, created when planning ahead.
+ *
+ * @return The next path executor
+ */
+ IPathExecutor getNext();
}
diff --git a/src/api/java/baritone/api/cache/ICachedRegion.java b/src/api/java/baritone/api/cache/ICachedRegion.java
index 5f9199fa..6b9048a5 100644
--- a/src/api/java/baritone/api/cache/ICachedRegion.java
+++ b/src/api/java/baritone/api/cache/ICachedRegion.java
@@ -29,11 +29,10 @@ public interface ICachedRegion extends IBlockTypeAccess {
* however, the block coordinates should in on a scale from 0 to 511 (inclusive)
* because region sizes are 512x512 blocks.
*
- * @see ICachedWorld#isCached(int, int)
- *
* @param blockX The block X coordinate
* @param blockZ The block Z coordinate
* @return Whether or not the specified XZ location is cached
+ * @see ICachedWorld#isCached(int, int)
*/
boolean isCached(int blockX, int blockZ);
diff --git a/src/api/java/baritone/api/cache/ICachedWorld.java b/src/api/java/baritone/api/cache/ICachedWorld.java
index f8196ebb..5e06a475 100644
--- a/src/api/java/baritone/api/cache/ICachedWorld.java
+++ b/src/api/java/baritone/api/cache/ICachedWorld.java
@@ -61,8 +61,8 @@ public interface ICachedWorld {
* information that is returned by this method may not be up to date, because
* older cached chunks can contain data that is much more likely to have changed.
*
- * @param block The special block to search for
- * @param maximum The maximum number of position results to receive
+ * @param block The special block to search for
+ * @param maximum The maximum number of position results to receive
* @param maxRegionDistanceSq The maximum region distance, squared
* @return The locations found that match the special block
*/
diff --git a/src/api/java/baritone/api/cache/IWaypointCollection.java b/src/api/java/baritone/api/cache/IWaypointCollection.java
index 051b199e..4dd80a3e 100644
--- a/src/api/java/baritone/api/cache/IWaypointCollection.java
+++ b/src/api/java/baritone/api/cache/IWaypointCollection.java
@@ -50,19 +50,17 @@ public interface IWaypointCollection {
/**
* Gets all of the waypoints that have the specified tag
*
- * @see IWaypointCollection#getAllWaypoints()
- *
* @param tag The tag
* @return All of the waypoints with the specified tag
+ * @see IWaypointCollection#getAllWaypoints()
*/
Set getByTag(IWaypoint.Tag tag);
/**
* Gets all of the waypoints in this collection, regardless of the tag.
*
- * @see IWaypointCollection#getByTag(IWaypoint.Tag)
- *
* @return All of the waypoints in this collection
+ * @see IWaypointCollection#getByTag(IWaypoint.Tag)
*/
Set getAllWaypoints();
}
diff --git a/src/api/java/baritone/api/cache/IWorldScanner.java b/src/api/java/baritone/api/cache/IWorldScanner.java
new file mode 100644
index 00000000..510e69ed
--- /dev/null
+++ b/src/api/java/baritone/api/cache/IWorldScanner.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.cache;
+
+import net.minecraft.block.Block;
+import net.minecraft.util.math.BlockPos;
+
+import java.util.List;
+
+/**
+ * @author Brady
+ * @since 10/6/2018
+ */
+public interface IWorldScanner {
+
+ /**
+ * Scans the world, up to the specified max chunk radius, for the specified blocks.
+ *
+ * @param blocks The blocks to scan for
+ * @param max The maximum number of blocks to scan before cutoff
+ * @param yLevelThreshold If a block is found within this Y level, the current result will be
+ * returned, if the value is negative, then this condition doesn't apply.
+ * @param maxSearchRadius The maximum chunk search radius
+ * @return The matching block positions
+ */
+ List scanChunkRadius(List blocks, int max, int yLevelThreshold, int maxSearchRadius);
+}
diff --git a/src/api/java/baritone/api/event/events/BlockInteractEvent.java b/src/api/java/baritone/api/event/events/BlockInteractEvent.java
index cc98a6ba..fbdadba1 100644
--- a/src/api/java/baritone/api/event/events/BlockInteractEvent.java
+++ b/src/api/java/baritone/api/event/events/BlockInteractEvent.java
@@ -20,6 +20,8 @@ package baritone.api.event.events;
import net.minecraft.util.math.BlockPos;
/**
+ * Called when the local player interacts with a block, can be either {@link Type#BREAK} or {@link Type#USE}.
+ *
* @author Brady
* @since 8/22/2018
*/
diff --git a/src/api/java/baritone/api/event/events/ChatEvent.java b/src/api/java/baritone/api/event/events/ChatEvent.java
index e103377f..ede83f24 100644
--- a/src/api/java/baritone/api/event/events/ChatEvent.java
+++ b/src/api/java/baritone/api/event/events/ChatEvent.java
@@ -17,20 +17,22 @@
package baritone.api.event.events;
-import baritone.api.event.events.type.Cancellable;
+import baritone.api.event.events.type.ManagedPlayerEvent;
+import net.minecraft.client.entity.EntityPlayerSP;
/**
* @author Brady
* @since 8/1/2018 6:39 PM
*/
-public final class ChatEvent extends Cancellable {
+public final class ChatEvent extends ManagedPlayerEvent.Cancellable {
/**
* The message being sent
*/
private final String message;
- public ChatEvent(String message) {
+ public ChatEvent(EntityPlayerSP player, String message) {
+ super(player);
this.message = message;
}
diff --git a/src/api/java/baritone/api/event/events/PacketEvent.java b/src/api/java/baritone/api/event/events/PacketEvent.java
index 9516db4b..9a3d2315 100644
--- a/src/api/java/baritone/api/event/events/PacketEvent.java
+++ b/src/api/java/baritone/api/event/events/PacketEvent.java
@@ -18,6 +18,7 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
+import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
/**
@@ -26,15 +27,22 @@ import net.minecraft.network.Packet;
*/
public final class PacketEvent {
+ private final NetworkManager networkManager;
+
private final EventState state;
private final Packet> packet;
- public PacketEvent(EventState state, Packet> packet) {
+ public PacketEvent(NetworkManager networkManager, EventState state, Packet> packet) {
+ this.networkManager = networkManager;
this.state = state;
this.packet = packet;
}
+ public final NetworkManager getNetworkManager() {
+ return this.networkManager;
+ }
+
public final EventState getState() {
return this.state;
}
diff --git a/src/api/java/baritone/api/event/events/PlayerUpdateEvent.java b/src/api/java/baritone/api/event/events/PlayerUpdateEvent.java
index 6ac08bdd..99370552 100644
--- a/src/api/java/baritone/api/event/events/PlayerUpdateEvent.java
+++ b/src/api/java/baritone/api/event/events/PlayerUpdateEvent.java
@@ -18,19 +18,22 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
+import baritone.api.event.events.type.ManagedPlayerEvent;
+import net.minecraft.client.entity.EntityPlayerSP;
/**
* @author Brady
* @since 8/21/2018
*/
-public final class PlayerUpdateEvent {
+public final class PlayerUpdateEvent extends ManagedPlayerEvent {
/**
* The state of the event
*/
private final EventState state;
- public PlayerUpdateEvent(EventState state) {
+ public PlayerUpdateEvent(EntityPlayerSP player, EventState state) {
+ super(player);
this.state = state;
}
diff --git a/src/api/java/baritone/api/event/events/RotationMoveEvent.java b/src/api/java/baritone/api/event/events/RotationMoveEvent.java
index ef6d9b7e..790318e0 100644
--- a/src/api/java/baritone/api/event/events/RotationMoveEvent.java
+++ b/src/api/java/baritone/api/event/events/RotationMoveEvent.java
@@ -17,7 +17,8 @@
package baritone.api.event.events;
-import baritone.api.event.events.type.EventState;
+import baritone.api.event.events.type.ManagedPlayerEvent;
+import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
@@ -25,7 +26,7 @@ import net.minecraft.entity.EntityLivingBase;
* @author Brady
* @since 8/21/2018
*/
-public final class RotationMoveEvent {
+public final class RotationMoveEvent extends ManagedPlayerEvent {
/**
* The type of event
@@ -33,20 +34,30 @@ public final class RotationMoveEvent {
private final Type type;
/**
- * The state of the event
+ * The yaw rotation
*/
- private final EventState state;
+ private float yaw;
- public RotationMoveEvent(EventState state, Type type) {
- this.state = state;
+ public RotationMoveEvent(EntityPlayerSP player, Type type, float yaw) {
+ super(player);
this.type = type;
+ this.yaw = yaw;
}
/**
- * @return The state of the event
+ * Set the yaw movement rotation
+ *
+ * @param yaw Yaw rotation
*/
- public final EventState getState() {
- return this.state;
+ public final void setYaw(float yaw) {
+ this.yaw = yaw;
+ }
+
+ /**
+ * @return The yaw rotation
+ */
+ public final float getYaw() {
+ return this.yaw;
}
/**
diff --git a/src/api/java/baritone/api/event/events/type/Cancellable.java b/src/api/java/baritone/api/event/events/type/Cancellable.java
index 331870c6..62ff9049 100644
--- a/src/api/java/baritone/api/event/events/type/Cancellable.java
+++ b/src/api/java/baritone/api/event/events/type/Cancellable.java
@@ -21,23 +21,19 @@ package baritone.api.event.events.type;
* @author Brady
* @since 8/1/2018 6:41 PM
*/
-public class Cancellable {
+public class Cancellable implements ICancellable {
/**
* Whether or not this event has been cancelled
*/
private boolean cancelled;
- /**
- * Cancels this event
- */
+ @Override
public final void cancel() {
this.cancelled = true;
}
- /**
- * @return Whether or not this event has been cancelled
- */
+ @Override
public final boolean isCancelled() {
return this.cancelled;
}
diff --git a/src/api/java/baritone/api/event/events/type/EventState.java b/src/api/java/baritone/api/event/events/type/EventState.java
index 10b633bd..072e12c1 100644
--- a/src/api/java/baritone/api/event/events/type/EventState.java
+++ b/src/api/java/baritone/api/event/events/type/EventState.java
@@ -24,14 +24,12 @@ package baritone.api.event.events.type;
public enum EventState {
/**
- * Indicates that whatever movement the event is being
- * dispatched as a result of is about to occur.
+ * Before the dispatching of what the event is targetting
*/
PRE,
/**
- * Indicates that whatever movement the event is being
- * dispatched as a result of has already occurred.
+ * After the dispatching of what the event is targetting
*/
POST
}
diff --git a/src/api/java/baritone/api/behavior/IFollowBehavior.java b/src/api/java/baritone/api/event/events/type/ICancellable.java
similarity index 63%
rename from src/api/java/baritone/api/behavior/IFollowBehavior.java
rename to src/api/java/baritone/api/event/events/type/ICancellable.java
index c960fab3..1df5cd79 100644
--- a/src/api/java/baritone/api/behavior/IFollowBehavior.java
+++ b/src/api/java/baritone/api/event/events/type/ICancellable.java
@@ -15,30 +15,21 @@
* along with Baritone. If not, see .
*/
-package baritone.api.behavior;
-
-import net.minecraft.entity.Entity;
+package baritone.api.event.events.type;
/**
* @author Brady
- * @since 9/23/2018
+ * @since 10/11/2018
*/
-public interface IFollowBehavior extends IBehavior {
+public interface ICancellable {
/**
- * 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.
+ * Cancels this event
*/
void cancel();
+
+ /**
+ * @return Whether or not this event has been cancelled
+ */
+ boolean isCancelled();
}
diff --git a/src/api/java/baritone/api/event/events/type/ManagedPlayerEvent.java b/src/api/java/baritone/api/event/events/type/ManagedPlayerEvent.java
new file mode 100644
index 00000000..a3487a67
--- /dev/null
+++ b/src/api/java/baritone/api/event/events/type/ManagedPlayerEvent.java
@@ -0,0 +1,61 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.event.events.type;
+
+import net.minecraft.client.entity.EntityPlayerSP;
+
+/**
+ * An event that has a reference to a locally managed player.
+ *
+ * @author Brady
+ * @since 10/11/2018
+ */
+public class ManagedPlayerEvent {
+
+ protected final EntityPlayerSP player;
+
+ public ManagedPlayerEvent(EntityPlayerSP player) {
+ this.player = player;
+ }
+
+ public final EntityPlayerSP getPlayer() {
+ return this.player;
+ }
+
+ public static class Cancellable extends ManagedPlayerEvent implements ICancellable {
+
+ /**
+ * Whether or not this event has been cancelled
+ */
+ private boolean cancelled;
+
+ public Cancellable(EntityPlayerSP player) {
+ super(player);
+ }
+
+ @Override
+ public final void cancel() {
+ this.cancelled = true;
+ }
+
+ @Override
+ public final boolean isCancelled() {
+ return this.cancelled;
+ }
+ }
+}
diff --git a/src/api/java/baritone/api/pathing/calc/IPath.java b/src/api/java/baritone/api/pathing/calc/IPath.java
new file mode 100644
index 00000000..0844ab90
--- /dev/null
+++ b/src/api/java/baritone/api/pathing/calc/IPath.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.pathing.calc;
+
+import baritone.api.Settings;
+import baritone.api.pathing.goals.Goal;
+import baritone.api.pathing.movement.IMovement;
+import baritone.api.utils.BetterBlockPos;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+
+import java.util.List;
+
+/**
+ * @author leijurv, Brady
+ */
+public interface IPath {
+
+ /**
+ * Ordered list of movements to carry out.
+ * movements.get(i).getSrc() should equal positions.get(i)
+ * movements.get(i).getDest() should equal positions.get(i+1)
+ * movements.size() should equal positions.size()-1
+ *
+ * @return All of the movements to carry out
+ */
+ List movements();
+
+ /**
+ * All positions along the way.
+ * Should begin with the same as getSrc and end with the same as getDest
+ *
+ * @return All of the positions along this path
+ */
+ List positions();
+
+ /**
+ * This path is actually going to be executed in the world. Do whatever additional processing is required.
+ * (as opposed to Path objects that are just constructed every frame for rendering)
+ */
+ default IPath postProcess() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the number of positions in this path. Equivalent to {@code positions().size()}.
+ *
+ * @return Number of positions in this path
+ */
+ default int length() {
+ return positions().size();
+ }
+
+ /**
+ * @return The goal that this path was calculated towards
+ */
+ Goal getGoal();
+
+ /**
+ * Returns the number of nodes that were considered during calculation before
+ * this path was found.
+ *
+ * @return The number of nodes that were considered before finding this path
+ */
+ int getNumNodesConsidered();
+
+ /**
+ * Returns the start position of this path. This is the first element in the
+ * {@link List} that is returned by {@link IPath#positions()}.
+ *
+ * @return The start position of this path
+ */
+ default BetterBlockPos getSrc() {
+ return positions().get(0);
+ }
+
+ /**
+ * Returns the end position of this path. This is the last element in the
+ * {@link List} that is returned by {@link IPath#positions()}.
+ *
+ * @return The end position of this path.
+ */
+ default BetterBlockPos getDest() {
+ List pos = positions();
+ return pos.get(pos.size() - 1);
+ }
+
+ /**
+ * Returns the estimated number of ticks to complete the path from the given node index.
+ *
+ * @param pathPosition The index of the node we're calculating from
+ * @return The estimated number of ticks remaining frm the given position
+ */
+ default double ticksRemainingFrom(int pathPosition) {
+ double sum = 0;
+ //this is fast because we aren't requesting recalculation, it's just cached
+ for (int i = pathPosition; i < movements().size(); i++) {
+ sum += movements().get(i).getCost();
+ }
+ return sum;
+ }
+
+ /**
+ * Cuts off this path at the loaded chunk border, and returns the resulting path. Default
+ * implementation just returns this path, without the intended functionality.
+ *
+ * @return The result of this cut-off operation
+ */
+ default IPath cutoffAtLoadedChunks(World world) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Cuts off this path using the min length and cutoff factor settings, and returns the resulting path.
+ * Default implementation just returns this path, without the intended functionality.
+ *
+ * @return The result of this cut-off operation
+ * @see Settings#pathCutoffMinimumLength
+ * @see Settings#pathCutoffFactor
+ */
+ default IPath staticCutoff(Goal destination) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ /**
+ * Performs a series of checks to ensure that the assembly of the path went as expected.
+ */
+ default void sanityCheck() {
+ List path = positions();
+ List movements = movements();
+ if (!getSrc().equals(path.get(0))) {
+ throw new IllegalStateException("Start node does not equal first path element");
+ }
+ if (!getDest().equals(path.get(path.size() - 1))) {
+ throw new IllegalStateException("End node does not equal last path element");
+ }
+ if (path.size() != movements.size() + 1) {
+ throw new IllegalStateException("Size of path array is unexpected");
+ }
+ for (int i = 0; i < path.size() - 1; i++) {
+ BlockPos src = path.get(i);
+ BlockPos dest = path.get(i + 1);
+ IMovement movement = movements.get(i);
+ if (!src.equals(movement.getSrc())) {
+ throw new IllegalStateException("Path source is not equal to the movement source");
+ }
+ if (!dest.equals(movement.getDest())) {
+ throw new IllegalStateException("Path destination is not equal to the movement destination");
+ }
+ }
+ }
+}
diff --git a/src/main/java/baritone/pathing/calc/IPathFinder.java b/src/api/java/baritone/api/pathing/calc/IPathFinder.java
similarity index 91%
rename from src/main/java/baritone/pathing/calc/IPathFinder.java
rename to src/api/java/baritone/api/pathing/calc/IPathFinder.java
index 6ed2b3a7..f70196a6 100644
--- a/src/main/java/baritone/pathing/calc/IPathFinder.java
+++ b/src/api/java/baritone/api/pathing/calc/IPathFinder.java
@@ -15,11 +15,10 @@
* along with Baritone. If not, see .
*/
-package baritone.pathing.calc;
+package baritone.api.pathing.calc;
import baritone.api.pathing.goals.Goal;
-import baritone.pathing.path.IPath;
-import net.minecraft.util.math.BlockPos;
+import baritone.api.utils.PathCalculationResult;
import java.util.Optional;
@@ -30,8 +29,6 @@ import java.util.Optional;
*/
public interface IPathFinder {
- BlockPos getStart();
-
Goal getGoal();
/**
@@ -39,7 +36,7 @@ public interface IPathFinder {
*
* @return The final path
*/
- Optional calculate(long timeout);
+ PathCalculationResult calculate(long timeout);
/**
* Intended to be called concurrently with calculatePath from a different thread to tell if it's finished yet
diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
index cb7a000e..44c5fa80 100644
--- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
+++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java
@@ -20,6 +20,7 @@ package baritone.api.pathing.goals;
import net.minecraft.util.math.BlockPos;
import java.util.Arrays;
+import java.util.Optional;
/**
* Useful for automated combat (retreating specifically)
@@ -32,16 +33,26 @@ public class GoalRunAway implements Goal {
private final double distanceSq;
+ private final Optional maintainY;
+
public GoalRunAway(double distance, BlockPos... from) {
+ this(distance, Optional.empty(), from);
+ }
+
+ public GoalRunAway(double distance, Optional maintainY, BlockPos... from) {
if (from.length == 0) {
throw new IllegalArgumentException();
}
this.from = from;
this.distanceSq = distance * distance;
+ this.maintainY = maintainY;
}
@Override
public boolean isInGoal(int x, int y, int z) {
+ if (maintainY.isPresent() && maintainY.get() != y) {
+ return false;
+ }
for (BlockPos p : from) {
int diffX = x - p.getX();
int diffZ = z - p.getZ();
@@ -62,11 +73,19 @@ public class GoalRunAway implements Goal {
min = h;
}
}
- return -min;
+ min = -min;
+ if (maintainY.isPresent()) {
+ min = min * 0.6 + GoalYLevel.calculate(maintainY.get(), y) * 1.5;
+ }
+ return min;
}
@Override
public String toString() {
- return "GoalRunAwayFrom" + Arrays.asList(from);
+ if (maintainY.isPresent()) {
+ return "GoalRunAwayFromMaintainY y=" + maintainY.get() + ", " + Arrays.asList(from);
+ } else {
+ return "GoalRunAwayFrom" + Arrays.asList(from);
+ }
}
}
diff --git a/src/api/java/baritone/api/pathing/movement/ActionCosts.java b/src/api/java/baritone/api/pathing/movement/ActionCosts.java
index e1f72dfa..683b1b10 100644
--- a/src/api/java/baritone/api/pathing/movement/ActionCosts.java
+++ b/src/api/java/baritone/api/pathing/movement/ActionCosts.java
@@ -23,21 +23,21 @@ 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_IN_WATER_COST = 20 / 2.2; // 9.091
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 LADDER_UP_ONE_COST = 20 / 2.35; // 8.511
+ double LADDER_DOWN_ONE_COST = 20 / 3.0; // 6.667
+ double SNEAK_ONE_BLOCK_COST = 20 / 1.3; // 15.385
double SPRINT_ONE_BLOCK_COST = 20 / 5.612; // 3.564
+ double SPRINT_MULTIPLIER = SPRINT_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST; // 0.769
/**
* 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;
+ double WALK_OFF_BLOCK_COST = WALK_ONE_BLOCK_COST * 0.8; // 3.706
/**
* 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;
+ double CENTER_AFTER_FALL_COST = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST; // 0.927
/**
* don't make this Double.MAX_VALUE because it's added to other things, maybe other COST_INFs,
diff --git a/src/api/java/baritone/api/pathing/movement/IMovement.java b/src/api/java/baritone/api/pathing/movement/IMovement.java
new file mode 100644
index 00000000..7b3eca5f
--- /dev/null
+++ b/src/api/java/baritone/api/pathing/movement/IMovement.java
@@ -0,0 +1,67 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.pathing.movement;
+
+import baritone.api.utils.BetterBlockPos;
+import net.minecraft.util.math.BlockPos;
+
+import java.util.List;
+
+/**
+ * @author Brady
+ * @since 10/8/2018
+ */
+public interface IMovement {
+
+ double getCost();
+
+ MovementStatus update();
+
+ /**
+ * Resets the current state status to {@link MovementStatus#PREPPING}
+ */
+ void reset();
+
+ /**
+ * Resets the cache for special break, place, and walk into blocks
+ */
+ void resetBlockCache();
+
+ /**
+ * @return Whether or not it is safe to cancel the current movement state
+ */
+ boolean safeToCancel();
+
+ double recalculateCost();
+
+ double calculateCostWithoutCaching();
+
+ boolean calculatedWhileLoaded();
+
+ BetterBlockPos getSrc();
+
+ BetterBlockPos getDest();
+
+ BlockPos getDirection();
+
+ List toBreak();
+
+ List toPlace();
+
+ List toWalkInto();
+}
diff --git a/src/api/java/baritone/api/pathing/movement/MovementStatus.java b/src/api/java/baritone/api/pathing/movement/MovementStatus.java
new file mode 100644
index 00000000..0190f8e1
--- /dev/null
+++ b/src/api/java/baritone/api/pathing/movement/MovementStatus.java
@@ -0,0 +1,74 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.pathing.movement;
+
+/**
+ * @author Brady
+ * @since 10/8/2018
+ */
+public enum MovementStatus {
+
+ /**
+ * We are preparing the movement to be executed. This is when any blocks obstructing the destination are broken.
+ */
+ PREPPING(false),
+
+ /**
+ * We are waiting for the movement to begin, after {@link MovementStatus#PREPPING}.
+ */
+ WAITING(false),
+
+ /**
+ * The movement is currently in progress, after {@link MovementStatus#WAITING}
+ */
+ RUNNING(false),
+
+ /**
+ * The movement has been completed and we are at our destination
+ */
+ SUCCESS(true),
+
+ /**
+ * There was a change in state between calculation and actual
+ * movement execution, and the movement has now become impossible.
+ */
+ UNREACHABLE(true),
+
+ /**
+ * Unused
+ */
+ FAILED(true),
+
+ /**
+ * "Unused"
+ */
+ CANCELED(true);
+
+ /**
+ * Whether or not this status indicates a complete movement.
+ */
+ private final boolean complete;
+
+ MovementStatus(boolean complete) {
+ this.complete = complete;
+ }
+
+ public final boolean isComplete() {
+ return this.complete;
+ }
+}
diff --git a/src/api/java/baritone/api/pathing/path/IPathExecutor.java b/src/api/java/baritone/api/pathing/path/IPathExecutor.java
new file mode 100644
index 00000000..f72060dc
--- /dev/null
+++ b/src/api/java/baritone/api/pathing/path/IPathExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.pathing.path;
+
+import baritone.api.pathing.calc.IPath;
+
+/**
+ * @author Brady
+ * @since 10/8/2018
+ */
+public interface IPathExecutor {
+
+ IPath getPath();
+}
diff --git a/src/api/java/baritone/api/process/IBaritoneProcess.java b/src/api/java/baritone/api/process/IBaritoneProcess.java
new file mode 100644
index 00000000..db7588ab
--- /dev/null
+++ b/src/api/java/baritone/api/process/IBaritoneProcess.java
@@ -0,0 +1,99 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.process;
+
+import baritone.api.IBaritone;
+import baritone.api.behavior.IPathingBehavior;
+import baritone.api.event.events.PathEvent;
+
+/**
+ * A process that can control the PathingBehavior.
+ *
+ * Differences between a baritone process and a behavior:
+ * Only one baritone process can be active at a time
+ * PathingBehavior can only be controlled by a process
+ *
+ * That's it actually
+ *
+ * @author leijurv
+ */
+public interface IBaritoneProcess {
+
+ /**
+ * Would this process like to be in control?
+ *
+ * @return Whether or not this process would like to be in contorl.
+ */
+ boolean isActive();
+
+ /**
+ * Called when this process is in control of pathing; Returns what Baritone should do.
+ *
+ * @param calcFailed {@code true} if this specific process was in control last tick,
+ * and there was a {@link PathEvent#CALC_FAILED} event last tick
+ * @param isSafeToCancel {@code true} if a {@link PathingCommandType#REQUEST_PAUSE} would happen this tick, and
+ * {@link IPathingBehavior} wouldn't actually tick. {@code false} if the PathExecutor reported
+ * pausing would be unsafe at the end of the last tick. Effectively "could request cancel or
+ * pause and have it happen right away"
+ * @return What the {@link IPathingBehavior} should do
+ */
+ PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel);
+
+ /**
+ * Returns whether or not this process should be treated as "temporary".
+ *
+ * If a process is temporary, it doesn't call {@link #onLostControl} on the processes that aren't execute because of it.
+ *
+ * For example, {@code CombatPauserProcess} and {@code PauseForAutoEatProcess} should return {@code true} always,
+ * and should return {@link #isActive} {@code true} only if there's something in range this tick, or if the player would like
+ * to start eating this tick. {@code PauseForAutoEatProcess} should only actually right click once onTick is called with
+ * {@code isSafeToCancel} true though.
+ *
+ * @return Whethor or not if this control is temporary
+ */
+ boolean isTemporary();
+
+ /**
+ * Called if {@link #isActive} returned {@code true}, but another non-temporary
+ * process has control. Effectively the same as cancel. You want control but you
+ * don't get it.
+ */
+ void onLostControl();
+
+ /**
+ * Used to determine which Process gains control if multiple are reporting {@link #isActive()}. The one
+ * that returns the highest value will be given control.
+ *
+ * @return A double representing the priority
+ */
+ double priority();
+
+ /**
+ * Returns which bot this process is associated with. (5000000iq forward thinking)
+ *
+ * @return The Bot associated with this process
+ */
+ IBaritone associatedWith();
+
+ /**
+ * Returns a user-friendly name for this process. Suitable for a HUD.
+ *
+ * @return A display name that's suitable for a HUD
+ */
+ String displayName();
+}
diff --git a/src/api/java/baritone/api/utils/interfaces/Toggleable.java b/src/api/java/baritone/api/process/ICustomGoalProcess.java
similarity index 54%
rename from src/api/java/baritone/api/utils/interfaces/Toggleable.java
rename to src/api/java/baritone/api/process/ICustomGoalProcess.java
index 359d6ee1..5084aff2 100644
--- a/src/api/java/baritone/api/utils/interfaces/Toggleable.java
+++ b/src/api/java/baritone/api/process/ICustomGoalProcess.java
@@ -15,40 +15,36 @@
* along with Baritone. If not, see .
*/
-package baritone.api.utils.interfaces;
+package baritone.api.process;
-/**
- * @author Brady
- * @since 8/20/2018
- */
-public interface Toggleable {
+import baritone.api.pathing.goals.Goal;
+
+public interface ICustomGoalProcess extends IBaritoneProcess {
/**
- * Toggles the enabled state of this {@link Toggleable}.
+ * Sets the pathing goal
*
- * @return The new state.
+ * @param goal The new goal
*/
- boolean toggle();
+ void setGoal(Goal goal);
/**
- * Sets the enabled state of this {@link Toggleable}.
+ * Starts path calculation and execution.
+ */
+ void path();
+
+ /**
+ * @return The current goal
+ */
+ Goal getGoal();
+
+ /**
+ * Sets the goal and begins the path execution.
*
- * @return The new state.
+ * @param goal The new goal
*/
- boolean setEnabled(boolean enabled);
-
- /**
- * @return Whether or not this {@link Toggleable} object is enabled
- */
- boolean isEnabled();
-
- /**
- * Called when the state changes from disabled to enabled
- */
- default void onEnable() {}
-
- /**
- * Called when the state changes from enabled to disabled
- */
- default void onDisable() {}
+ default void setGoalAndPath(Goal goal) {
+ this.setGoal(goal);
+ this.path();
+ }
}
diff --git a/src/launch/java/baritone/launch/BaritoneTweakerForge.java b/src/api/java/baritone/api/process/IFollowProcess.java
similarity index 50%
rename from src/launch/java/baritone/launch/BaritoneTweakerForge.java
rename to src/api/java/baritone/api/process/IFollowProcess.java
index 7623eed5..ef869da4 100644
--- a/src/launch/java/baritone/launch/BaritoneTweakerForge.java
+++ b/src/api/java/baritone/api/process/IFollowProcess.java
@@ -15,30 +15,37 @@
* along with Baritone. If not, see .
*/
-package baritone.launch;
+package baritone.api.process;
-import net.minecraft.launchwrapper.LaunchClassLoader;
-import org.spongepowered.asm.mixin.MixinEnvironment;
-import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
+import net.minecraft.entity.Entity;
-import java.io.File;
-import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
* @author Brady
- * @since 7/31/2018 10:09 PM
+ * @since 9/23/2018
*/
-public class BaritoneTweakerForge extends BaritoneTweaker {
+public interface IFollowProcess extends IBaritoneProcess {
- @Override
- public final void acceptOptions(List args, File gameDir, File assetsDir, String profile) {
- this.args = new ArrayList<>();
- }
+ /**
+ * Set the follow target to any entities matching this predicate
+ *
+ * @param filter the predicate
+ */
+ void follow(Predicate filter);
- @Override
- public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
- super.injectIntoClassLoader(classLoader);
- MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.SEARGE);
+ /**
+ * @return The entities that are currently being followed. null if not currently following, empty if nothing matches the predicate
+ */
+ List following();
+
+ Predicate currentFilter();
+
+ /**
+ * Cancels the follow behavior, this will clear the current follow target.
+ */
+ default void cancel() {
+ onLostControl();
}
}
diff --git a/src/api/java/baritone/api/process/IGetToBlockProcess.java b/src/api/java/baritone/api/process/IGetToBlockProcess.java
new file mode 100644
index 00000000..ff3dc9b5
--- /dev/null
+++ b/src/api/java/baritone/api/process/IGetToBlockProcess.java
@@ -0,0 +1,28 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.process;
+
+import net.minecraft.block.Block;
+
+/**
+ * but it rescans the world every once in a while so it doesn't get fooled by its cache
+ */
+public interface IGetToBlockProcess extends IBaritoneProcess {
+
+ void getToBlock(Block block);
+}
diff --git a/src/api/java/baritone/api/behavior/IMineBehavior.java b/src/api/java/baritone/api/process/IMineProcess.java
similarity index 81%
rename from src/api/java/baritone/api/behavior/IMineBehavior.java
rename to src/api/java/baritone/api/process/IMineProcess.java
index 78ab6d6a..7ebabc9c 100644
--- a/src/api/java/baritone/api/behavior/IMineBehavior.java
+++ b/src/api/java/baritone/api/process/IMineProcess.java
@@ -15,7 +15,7 @@
* along with Baritone. If not, see .
*/
-package baritone.api.behavior;
+package baritone.api.process;
import net.minecraft.block.Block;
@@ -23,7 +23,7 @@ import net.minecraft.block.Block;
* @author Brady
* @since 9/23/2018
*/
-public interface IMineBehavior extends IBehavior {
+public interface IMineProcess extends IBaritoneProcess {
/**
* Begin to search for and mine the specified blocks until
@@ -31,9 +31,9 @@ public interface IMineBehavior extends IBehavior {
* are mined. This is based on the first target block to mine.
*
* @param quantity The number of items to get from blocks mined
- * @param blocks The blocks to mine
+ * @param blocks The blocks to mine
*/
- void mine(int quantity, String... blocks);
+ void mineByName(int quantity, String... blocks);
/**
* Begin to search for and mine the specified blocks until
@@ -41,7 +41,7 @@ public interface IMineBehavior extends IBehavior {
* are mined. This is based on the first target block to mine.
*
* @param quantity The number of items to get from blocks mined
- * @param blocks The blocks to mine
+ * @param blocks The blocks to mine
*/
void mine(int quantity, Block... blocks);
@@ -50,8 +50,8 @@ public interface IMineBehavior extends IBehavior {
*
* @param blocks The blocks to mine
*/
- default void mine(String... blocks) {
- this.mine(0, blocks);
+ default void mineByName(String... blocks) {
+ mineByName(0, blocks);
}
/**
@@ -60,11 +60,13 @@ public interface IMineBehavior extends IBehavior {
* @param blocks The blocks to mine
*/
default void mine(Block... blocks) {
- this.mine(0, blocks);
+ mine(0, blocks);
}
/**
* Cancels the current mining task
*/
- void cancel();
+ default void cancel() {
+ onLostControl();
+ }
}
diff --git a/src/api/java/baritone/api/process/PathingCommand.java b/src/api/java/baritone/api/process/PathingCommand.java
new file mode 100644
index 00000000..2caef158
--- /dev/null
+++ b/src/api/java/baritone/api/process/PathingCommand.java
@@ -0,0 +1,56 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.process;
+
+import baritone.api.pathing.goals.Goal;
+
+import java.util.Objects;
+
+/**
+ * @author leijurv
+ */
+public class PathingCommand {
+
+ /**
+ * The target goal, may be {@code null}.
+ */
+ public final Goal goal;
+
+ /**
+ * The command type.
+ *
+ * @see PathingCommandType
+ */
+ public final PathingCommandType commandType;
+
+ /**
+ * Create a new {@link PathingCommand}.
+ *
+ * @param goal The target goal, may be {@code null}.
+ * @param commandType The command type, cannot be {@code null}.
+ * @throws NullPointerException if {@code commandType} is {@code null}.
+ * @see Goal
+ * @see PathingCommandType
+ */
+ public PathingCommand(Goal goal, PathingCommandType commandType) {
+ Objects.requireNonNull(commandType);
+
+ this.goal = goal;
+ this.commandType = commandType;
+ }
+}
diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java
new file mode 100644
index 00000000..da64748a
--- /dev/null
+++ b/src/api/java/baritone/api/process/PathingCommandType.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.process;
+
+import baritone.api.Settings;
+
+public enum PathingCommandType {
+
+ /**
+ * Set the goal and path.
+ *
+ * If you use this alongside a {@code null} goal, it will continue along its current path and current goal.
+ */
+ SET_GOAL_AND_PATH,
+
+ /**
+ * Has no effect on the current goal or path, just requests a pause
+ */
+ REQUEST_PAUSE,
+
+ /**
+ * Set the goal (regardless of {@code null}), and request a cancel of the current path (when safe)
+ */
+ CANCEL_AND_SET_GOAL,
+
+ /**
+ * Set the goal and path.
+ *
+ * If {@link Settings#cancelOnGoalInvalidation} is {@code true}, revalidate the
+ * current goal, and cancel if it's no longer valid, or if the new goal is {@code null}.
+ */
+ REVALIDATE_GOAL_AND_PATH,
+
+ /**
+ * Set the goal and path.
+ *
+ * Cancel the current path if the goals are not equal
+ */
+ FORCE_REVALIDATE_GOAL_AND_PATH
+}
diff --git a/src/main/java/baritone/utils/pathing/BetterBlockPos.java b/src/api/java/baritone/api/utils/BetterBlockPos.java
similarity index 85%
rename from src/main/java/baritone/utils/pathing/BetterBlockPos.java
rename to src/api/java/baritone/api/utils/BetterBlockPos.java
index 5e8682c9..3aa6a71d 100644
--- a/src/main/java/baritone/utils/pathing/BetterBlockPos.java
+++ b/src/api/java/baritone/api/utils/BetterBlockPos.java
@@ -15,9 +15,8 @@
* along with Baritone. If not, see .
*/
-package baritone.utils.pathing;
+package baritone.api.utils;
-import baritone.pathing.calc.AbstractNodeCostSearch;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
@@ -36,7 +35,6 @@ public final class BetterBlockPos extends BlockPos {
public final int x;
public final int y;
public final int z;
- public final long hashCode;
public static long numCreated;
static {
@@ -52,7 +50,6 @@ public final class BetterBlockPos extends BlockPos {
this.x = x;
this.y = y;
this.z = z;
- this.hashCode = AbstractNodeCostSearch.posHash(x, y, z);
}
public BetterBlockPos(double x, double y, double z) {
@@ -65,7 +62,30 @@ public final class BetterBlockPos extends BlockPos {
@Override
public int hashCode() {
- return (int) hashCode;
+ return (int) longHash(x, y, z);
+ }
+
+ public static long longHash(BetterBlockPos pos) {
+ return longHash(pos.x, pos.y, pos.z);
+ }
+
+ public static long longHash(int x, int y, int z) {
+ /*
+ * This is the hashcode implementation of Vec3i (the superclass of the class which I shall not name)
+ *
+ * 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;
}
@Override
@@ -75,9 +95,6 @@ public final class BetterBlockPos extends BlockPos {
}
if (o instanceof BetterBlockPos) {
BetterBlockPos oth = (BetterBlockPos) o;
- if (oth.hashCode != hashCode) {
- return false;
- }
return oth.x == x && oth.y == y && oth.z == z;
}
// during path execution, like "if (whereShouldIBe.equals(whereAmI)) {"
diff --git a/src/api/java/baritone/api/utils/PathCalculationResult.java b/src/api/java/baritone/api/utils/PathCalculationResult.java
new file mode 100644
index 00000000..69d2a9b3
--- /dev/null
+++ b/src/api/java/baritone/api/utils/PathCalculationResult.java
@@ -0,0 +1,41 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.utils;
+
+import baritone.api.pathing.calc.IPath;
+
+import java.util.Optional;
+
+public class PathCalculationResult {
+
+ public final Optional path;
+ public final Type type;
+
+ public PathCalculationResult(Type type, Optional path) {
+ this.path = path;
+ this.type = type;
+ }
+
+ public enum Type {
+ SUCCESS_TO_GOAL,
+ SUCCESS_SEGMENT,
+ FAILURE,
+ CANCELLATION,
+ EXCEPTION,
+ }
+}
diff --git a/src/api/java/baritone/api/utils/RayTraceUtils.java b/src/api/java/baritone/api/utils/RayTraceUtils.java
new file mode 100644
index 00000000..8b37ef9d
--- /dev/null
+++ b/src/api/java/baritone/api/utils/RayTraceUtils.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.utils;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.RayTraceResult;
+import net.minecraft.util.math.Vec3d;
+
+import java.util.Optional;
+
+/**
+ * @author Brady
+ * @since 8/25/2018
+ */
+public final class RayTraceUtils {
+
+ private static final Minecraft mc = Minecraft.getMinecraft();
+
+ private RayTraceUtils() {}
+
+ /**
+ * 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(Entity entity, Rotation rotation, double blockReachDistance) {
+ Vec3d start = entity.getPositionEyes(1.0F);
+ Vec3d direction = RotationUtils.calcVec3dFromRotation(rotation);
+ Vec3d end = start.add(
+ direction.x * blockReachDistance,
+ direction.y * blockReachDistance,
+ direction.z * blockReachDistance
+ );
+ return mc.world.rayTraceBlocks(start, end, false, false, true);
+ }
+
+ /**
+ * Returns the block that the crosshair is currently placed over. Updated once per render tick.
+ *
+ * @return The position of the highlighted block
+ */
+ public static Optional getSelectedBlock() {
+ if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) {
+ return Optional.of(mc.objectMouseOver.getBlockPos());
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns the entity that the crosshair is currently placed over. Updated once per render tick.
+ *
+ * @return The entity
+ */
+ public static Optional getSelectedEntity() {
+ if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
+ return Optional.of(mc.objectMouseOver.entityHit);
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/api/java/baritone/api/utils/Rotation.java b/src/api/java/baritone/api/utils/Rotation.java
index dc697169..ea10c7ec 100644
--- a/src/api/java/baritone/api/utils/Rotation.java
+++ b/src/api/java/baritone/api/utils/Rotation.java
@@ -86,7 +86,7 @@ public class Rotation {
public Rotation clamp() {
return new Rotation(
this.yaw,
- RotationUtils.clampPitch(this.pitch)
+ clampPitch(this.pitch)
);
}
@@ -95,7 +95,7 @@ public class Rotation {
*/
public Rotation normalize() {
return new Rotation(
- RotationUtils.normalizeYaw(this.yaw),
+ normalizeYaw(this.yaw),
this.pitch
);
}
@@ -105,8 +105,35 @@ public class Rotation {
*/
public Rotation normalizeAndClamp() {
return new Rotation(
- RotationUtils.normalizeYaw(this.yaw),
- RotationUtils.clampPitch(this.pitch)
+ normalizeYaw(this.yaw),
+ clampPitch(this.pitch)
);
}
+
+ /**
+ * Clamps the specified pitch value between -90 and 90.
+ *
+ * @param pitch The input pitch
+ * @return The clamped pitch
+ */
+ public static float clampPitch(float pitch) {
+ return Math.max(-90, Math.min(90, pitch));
+ }
+
+ /**
+ * Normalizes the specified yaw value between -180 and 180.
+ *
+ * @param yaw The input yaw
+ * @return The normalized yaw
+ */
+ public static float normalizeYaw(float yaw) {
+ float newYaw = yaw % 360F;
+ if (newYaw < -180F) {
+ newYaw += 360F;
+ }
+ if (newYaw >= 180F) {
+ newYaw -= 360F;
+ }
+ return newYaw;
+ }
}
diff --git a/src/api/java/baritone/api/utils/RotationUtils.java b/src/api/java/baritone/api/utils/RotationUtils.java
index 0df4b38d..e1726812 100644
--- a/src/api/java/baritone/api/utils/RotationUtils.java
+++ b/src/api/java/baritone/api/utils/RotationUtils.java
@@ -17,38 +17,192 @@
package baritone.api.utils;
+import net.minecraft.block.BlockFire;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.math.*;
+
+import java.util.Optional;
+
/**
* @author Brady
* @since 9/25/2018
*/
public final class RotationUtils {
+ /**
+ * Constant that a degree value is multiplied by to get the equivalent radian value
+ */
+ public static final double DEG_TO_RAD = Math.PI / 180.0;
+
+ /**
+ * Constant that a radian value is multiplied by to get the equivalent degree value
+ */
+ public static final double RAD_TO_DEG = 180.0 / Math.PI;
+
+ /**
+ * Offsets from the root block position to the center of each side.
+ */
+ private static final Vec3d[] BLOCK_SIDE_MULTIPLIERS = new Vec3d[]{
+ new Vec3d(0.5, 0, 0.5), // Down
+ new Vec3d(0.5, 1, 0.5), // Up
+ new Vec3d(0.5, 0.5, 0), // North
+ new Vec3d(0.5, 0.5, 1), // South
+ new Vec3d(0, 0.5, 0.5), // West
+ new Vec3d(1, 0.5, 0.5) // East
+ };
+
private RotationUtils() {}
/**
- * Clamps the specified pitch value between -90 and 90.
+ * Calculates the rotation from BlockPosdest to BlockPosorig
*
- * @param pitch The input pitch
- * @return The clamped pitch
+ * @param orig The origin position
+ * @param dest The destination position
+ * @return The rotation from the origin to the destination
*/
- public static float clampPitch(float pitch) {
- return Math.max(-90, Math.min(90, pitch));
+ public static Rotation calcRotationFromCoords(BlockPos orig, BlockPos dest) {
+ return calcRotationFromVec3d(new Vec3d(orig), new Vec3d(dest));
}
/**
- * Normalizes the specified yaw value between -180 and 180.
+ * Wraps the target angles to a relative value from the current angles. This is done by
+ * subtracting the current from the target, normalizing it, and then adding the current
+ * angles back to it.
*
- * @param yaw The input yaw
- * @return The normalized yaw
+ * @param current The current angles
+ * @param target The target angles
+ * @return The wrapped angles
*/
- public static float normalizeYaw(float yaw) {
- float newYaw = yaw % 360F;
- if (newYaw < -180F) {
- newYaw += 360F;
+ public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) {
+ return target.subtract(current).normalize().add(current);
+ }
+
+ /**
+ * Calculates the rotation from Vecdest to Vecorig and makes the
+ * return value relative to the specified current rotations.
+ *
+ * @param orig The origin position
+ * @param dest The destination position
+ * @param current The current rotations
+ * @return The rotation from the origin to the destination
+ * @see #wrapAnglesToRelative(Rotation, Rotation)
+ */
+ public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest, Rotation current) {
+ return wrapAnglesToRelative(current, calcRotationFromVec3d(orig, dest));
+ }
+
+ /**
+ * Calculates the rotation from Vecdest to Vecorig
+ *
+ * @param orig The origin position
+ * @param dest The destination position
+ * @return The rotation from the origin to the destination
+ */
+ public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) {
+ double[] delta = {orig.x - dest.x, orig.y - dest.y, orig.z - dest.z};
+ double yaw = MathHelper.atan2(delta[0], -delta[2]);
+ double dist = Math.sqrt(delta[0] * delta[0] + delta[2] * delta[2]);
+ double pitch = MathHelper.atan2(delta[1], dist);
+ return new Rotation(
+ (float) (yaw * RAD_TO_DEG),
+ (float) (pitch * RAD_TO_DEG)
+ );
+ }
+
+ /**
+ * Calculates the look vector for the specified yaw/pitch rotations.
+ *
+ * @param rotation The input rotation
+ * @return Look vector for the rotation
+ */
+ public static Vec3d calcVec3dFromRotation(Rotation rotation) {
+ float f = MathHelper.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
+ float f1 = MathHelper.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
+ float f2 = -MathHelper.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
+ float f3 = MathHelper.sin(-rotation.getPitch() * (float) DEG_TO_RAD);
+ return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
+ }
+
+ /**
+ * Determines if the specified entity is able to reach the center of any of the sides
+ * of the specified block. It first checks if the block center is reachable, and if so,
+ * that rotation will be returned. If not, it will return the first center of a given
+ * side that is reachable. The return type will be {@link Optional#empty()} if the entity is
+ * unable to reach any of the sides of the block.
+ *
+ * @param entity The viewing entity
+ * @param pos The target block position
+ * @return The optional rotation
+ */
+ public static Optional reachable(Entity entity, BlockPos pos, double blockReachDistance) {
+ if (pos.equals(RayTraceUtils.getSelectedBlock().orElse(null))) {
+ /*
+ * why add 0.0001?
+ * to indicate that we actually have a desired pitch
+ * the way we indicate that the pitch can be whatever and we only care about the yaw
+ * is by setting the desired pitch to the current pitch
+ * setting the desired pitch to the current pitch + 0.0001 means that we do have a desired pitch, it's
+ * just what it currently is
+ *
+ * or if you're a normal person literally all this does it ensure that we don't nudge the pitch to a normal level
+ */
+ return Optional.of(new Rotation(entity.rotationYaw, entity.rotationPitch + 0.0001F));
}
- if (newYaw >= 180F) {
- newYaw -= 360F;
+ Optional possibleRotation = reachableCenter(entity, pos, blockReachDistance);
+ //System.out.println("center: " + possibleRotation);
+ if (possibleRotation.isPresent()) {
+ return possibleRotation;
}
- return newYaw;
+
+ IBlockState state = entity.world.getBlockState(pos);
+ AxisAlignedBB aabb = state.getBoundingBox(entity.world, pos);
+ for (Vec3d sideOffset : BLOCK_SIDE_MULTIPLIERS) {
+ double xDiff = aabb.minX * sideOffset.x + aabb.maxX * (1 - sideOffset.x);
+ double yDiff = aabb.minY * sideOffset.y + aabb.maxY * (1 - sideOffset.y);
+ double zDiff = aabb.minZ * sideOffset.z + aabb.maxZ * (1 - sideOffset.z);
+ possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff), blockReachDistance);
+ if (possibleRotation.isPresent()) {
+ return possibleRotation;
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Determines if the specified entity is able to reach the specified block with
+ * the given offsetted position. The return type will be {@link Optional#empty()} if
+ * the entity is unable to reach the block with the offset applied.
+ *
+ * @param entity The viewing entity
+ * @param pos The target block position
+ * @param offsetPos The position of the block with the offset applied.
+ * @return The optional rotation
+ */
+ public static Optional reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) {
+ Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos);
+ RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance);
+ //System.out.println(result);
+ if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
+ if (result.getBlockPos().equals(pos)) {
+ return Optional.of(rotation);
+ }
+ if (entity.world.getBlockState(pos).getBlock() instanceof BlockFire && result.getBlockPos().equals(pos.down())) {
+ return Optional.of(rotation);
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Determines if the specified entity is able to reach the specified block where it is
+ * looking at the direct center of it's hitbox.
+ *
+ * @param entity The viewing entity
+ * @param pos The target block position
+ * @return The optional rotation
+ */
+ public static Optional reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) {
+ return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(pos), blockReachDistance);
}
}
diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java
new file mode 100644
index 00000000..4d13d027
--- /dev/null
+++ b/src/api/java/baritone/api/utils/SettingsUtil.java
@@ -0,0 +1,141 @@
+/*
+ * This file is part of Baritone.
+ *
+ * Baritone is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Baritone is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Baritone. If not, see .
+ */
+
+package baritone.api.utils;
+
+import baritone.api.Settings;
+import net.minecraft.client.Minecraft;
+import net.minecraft.item.Item;
+import net.minecraft.util.ResourceLocation;
+
+import java.awt.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class SettingsUtil {
+
+ private static final File settingsFile = new File(new File(Minecraft.getMinecraft().gameDir, "baritone"), "settings.txt");
+
+ private static final Map, SettingsIO> map;
+
+ public static void readAndApply(Settings settings) {
+ try (Scanner scan = new Scanner(settingsFile)) {
+ while (scan.hasNextLine()) {
+ String line = scan.nextLine();
+ if (line.isEmpty()) {
+ continue;
+ }
+ if (line.startsWith("#") || line.startsWith("//")) {
+ continue;
+ }
+ int space = line.indexOf(" ");
+ if (space == -1) {
+ System.out.println("Skipping invalid line with no space: " + line);
+ continue;
+ }
+ String settingName = line.substring(0, space).trim().toLowerCase();
+ String settingValue = line.substring(space).trim();
+ try {
+ parseAndApply(settings, settingName, settingValue);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.out.println("Unable to parse line " + line);
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
+ }
+ }
+
+ public static synchronized void save(Settings settings) {
+ try (FileOutputStream out = new FileOutputStream(settingsFile)) {
+ for (Settings.Setting setting : settings.allSettings) {
+ if (setting.get() == null) {
+ System.out.println("NULL SETTING?" + setting.getName());
+ continue;
+ }
+ if (setting.getName().equals("logger")) {
+ continue; // NO
+ }
+ if (setting.value == setting.defaultValue) {
+ continue;
+ }
+ SettingsIO io = map.get(setting.getValueClass());
+ if (io == null) {
+ throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName());
+ }
+ out.write((setting.getName() + " " + io.toString.apply(setting.get()) + "\n").getBytes());
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.out.println("Exception while saving Baritone settings!");
+ }
+ }
+
+ private static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
+ Settings.Setting setting = settings.byLowerName.get(settingName);
+ if (setting == null) {
+ throw new IllegalStateException("No setting by that name");
+ }
+ Class intendedType = setting.getValueClass();
+ SettingsIO ioMethod = map.get(intendedType);
+ Object parsed = ioMethod.parser.apply(settingValue);
+ if (!intendedType.isInstance(parsed)) {
+ throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass());
+ }
+ setting.value = parsed;
+ }
+
+ private enum SettingsIO {
+ DOUBLE(Double.class, Double::parseDouble),
+ BOOLEAN(Boolean.class, Boolean::parseBoolean),
+ INTEGER(Integer.class, Integer::parseInt),
+ FLOAT(Float.class, Float::parseFloat),
+ LONG(Long.class, Long::parseLong),
+
+ ITEM_LIST(ArrayList.class, str -> Stream.of(str.split(",")).map(Item::getByNameOrId).collect(Collectors.toCollection(ArrayList::new)), list -> ((ArrayList) list).stream().map(Item.REGISTRY::getNameForObject).map(ResourceLocation::toString).collect(Collectors.joining(","))),
+ COLOR(Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), color -> color.getRed() + "," + color.getGreen() + "," + color.getBlue());
+
+
+ Class> klass;
+ Function parser;
+ Function