Compare commits

..

61 Commits

Author SHA1 Message Date
Leijurv 060741bfdc fixes 2018-11-24 19:17:30 -08:00
Leijurv 2a21a1ca18 simplify 2018-11-24 12:53:09 -08:00
Leijurv 8ece179912 recalculate on allocation size change 2018-11-24 11:32:23 -08:00
Leijurv c79f40a5f1 tenor comms integration, and priority allocation caching 2018-11-24 11:01:23 -08:00
Leijurv 3b7e1adf24 add default lol 2018-11-23 19:24:14 -08:00
Leijurv 01bec5d8f9 computation requests on the tenor side 2018-11-23 19:06:35 -08:00
Leijurv 82c64d4d06 Merge branch 'comms' into tenor 2018-11-23 16:35:35 -08:00
Leijurv 11e44acf65 helper to handle pending msgs 2018-11-23 16:35:03 -08:00
Leijurv c73751ef98 Merge branch 'comms' into tenor 2018-11-23 16:10:06 -08:00
Leijurv 16fec4a1a0 buffered connection creation helper 2018-11-23 16:09:59 -08:00
Leijurv 81c95a2d43 fix tenor build after comms refactor 2018-11-23 13:36:06 -08:00
Leijurv 07970f803f Merge branch 'calc-request' into tenor 2018-11-23 13:35:03 -08:00
Leijurv 5ae4f23886 Merge branch 'comms' into calc-request 2018-11-23 13:34:48 -08:00
Leijurv f222980a1a move comms to cabaletta.comms 2018-11-23 13:32:18 -08:00
Leijurv 7f1fb2a8fe Merge branch 'calc-request' into tenor 2018-11-23 13:17:42 -08:00
Leijurv c57f65f832 complete new segmented calculation system 2018-11-23 13:17:03 -08:00
Leijurv 85a6ec022e Merge branch 'comms' into calc-request 2018-11-23 13:13:35 -08:00
Leijurv c1032da828 Merge branch 'master' into comms 2018-11-23 13:12:38 -08:00
Leijurv 806c2a4af1 tenor dependency on comms 2018-11-23 13:08:38 -08:00
Leijurv c5ecb9bb9b Merge branch 'calc-request' into tenor 2018-11-23 12:57:08 -08:00
Leijurv e0d894d296 computation request and response 2018-11-23 12:09:35 -08:00
Leijurv 27c818f873 Merge branch 'comms' into calc-request 2018-11-23 11:49:49 -08:00
Leijurv fdd758bc90 too much log spam 2018-11-23 11:48:01 -08:00
Leijurv 3a2620192b too much log spam 2018-11-23 11:46:47 -08:00
Leijurv c423d5f575 report path start position 2018-11-23 11:35:13 -08:00
Leijurv 81a9b71429 Merge branch 'segment-calculation' into comms 2018-11-23 10:36:56 -08:00
Leijurv 81ecc209d3 synchronize partial reads and writes to a socket 2018-11-23 10:09:13 -08:00
Leijurv 0dc67593bb lots more status 2018-11-18 21:56:46 -08:00
Leijurv 2e180e81ed Merge branch 'comms' of github.com:cabaletta/baritone into comms 2018-11-18 21:42:04 -08:00
Leijurv 0b11057449 Merge branch 'master' into comms 2018-11-18 21:41:50 -08:00
Brady 186652a8d8 Protocol lol 2018-11-18 19:52:11 -06:00
Leijurv 18d8cfb6de Merge branch 'master' into comms 2018-11-18 17:39:26 -08:00
Leijurv f99befd307 oh thats important 2018-11-18 12:04:37 -08:00
Leijurv 9ad35dbf28 remove the useless stuff 2018-11-18 11:35:54 -08:00
Leijurv dfb49179c5 not a handler lol 2018-11-18 11:27:53 -08:00
Brady 3c913a7b85 Fix jar export 2018-11-18 13:27:25 -06:00
Leijurv f01cf669e8 wtf 2018-11-18 11:06:40 -08:00
Leijurv 2d87033f49 f 2018-11-18 11:06:11 -08:00
Leijurv f014e42aa4 initial comms 2018-11-18 11:01:46 -08:00
Brady 46de72e28c Comms Sourceset 2018-11-17 18:07:16 -06:00
Leijurv 87a44e4093 Merge branch 'master' into tenor 2018-11-12 16:16:03 -08:00
Brady d082d25253 Tenor Sourceset 2018-11-12 18:09:57 -06:00
Leijurv 1cf6768e27 misc 2018-11-09 12:59:46 -08:00
Leijurv 890dbec852 bunch of stuff 2018-10-31 20:04:32 -07:00
Leijurv 24bb0c541c split up singular and quantized single parent priority allocators 2018-10-31 13:30:37 -07:00
Leijurv e7a09c34ea cleanup and combine single parent priority allocation 2018-10-31 13:19:48 -07:00
Brady 9642950b54 oppa 2018-10-30 20:30:44 -05:00
Brady f76736a378 Minecraft imports should only be in minecraft task implementations 2018-10-30 20:05:35 -05:00
Leijurv 91c6baead1 dont allocate parent tasks with empty priority 2018-10-30 17:42:58 -07:00
Leijurv e81b01a8f3 fix priority allocation method 2018-10-30 17:18:08 -07:00
Brady f2a45b9eeb Streams are nice 2018-10-30 18:21:09 -05:00
Leijurv 5e2ccdac08 i love generics 2018-10-30 15:44:52 -07:00
Leijurv 473f872d2f you are no longer being poisoned by a toxic cloud 2018-10-30 15:31:02 -07:00
Brady 3d03f15749 Fix bad interface naming 2018-10-30 17:30:03 -05:00
Leijurv 15e91c7c7c quite cool that this can now be done 2018-10-30 15:28:04 -07:00
Leijurv 5089c62ada generics LOL 2018-10-30 15:23:14 -07:00
Leijurv 7c69a188f6 pog 2018-10-30 15:07:16 -07:00
Leijurv ef6b36b2cc wew lad 2018-10-30 15:05:17 -07:00
Brady f2f806669c Generify pt 1 2018-10-30 15:51:19 -05:00
Leijurv c887b27df9 in too deep 2018-10-30 11:51:49 -07:00
Leijurv e1bb8fd570 here we go LOL 2018-10-29 23:15:08 -07:00
169 changed files with 4503 additions and 2700 deletions
-1
View File
@@ -9,7 +9,6 @@ install:
- travis_retry docker build -t cabaletta/baritone . - travis_retry docker build -t cabaletta/baritone .
script: script:
- docker run --rm cabaletta/baritone ./gradlew javadoc
- 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 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 - docker cp baritone:/code/dist dist
- ls dist - ls dist
+1 -1
View File
@@ -11,7 +11,6 @@
- **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. - **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** 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. - **Parkour place** Sprint jumping over a 3 block gap and placing the block to land on while executing the jump. It's really cool.
- **Pigs** It can sort of control pigs. I wouldn't rely on it though.
# Pathing method # Pathing method
Baritone uses A*, with some modifications: Baritone uses A*, with some modifications:
@@ -47,6 +46,7 @@ Things it doesn't have yet
See <a href="https://github.com/cabaletta/baritone/issues">issues</a> for more. See <a href="https://github.com/cabaletta/baritone/issues">issues</a> for more.
Things it may not ever have, from most likely to least likely =( Things it may not ever have, from most likely to least likely =(
- Pigs
- Boats - Boats
- Horses (2x3 path instead of 1x2) - Horses (2x3 path instead of 1x2)
- Elytra - Elytra
+1
View File
@@ -0,0 +1 @@
Impact 4.4 is out. See <a href="INSTALL.md">INSTALL.md</a>
+10 -2
View File
@@ -1,10 +1,11 @@
# Integration between Baritone and Impact # Integration between Baritone and Impact
Impact 4.4 has Baritone included. Impact 4.4 has Baritone included.
These instructions apply to Impact 4.3 (and potentially other "hacked clients"). 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`). To run Baritone on Vanilla, just follow the instructions in the README (it's `./gradlew runClient`).
## An Introduction ## An Introduction
There are some basic steps to getting Baritone setup with Impact. There are some basic steps to getting Baritone setup with Impact.
- Acquiring a build of Baritone - Acquiring a build of Baritone
@@ -25,7 +26,14 @@ Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMe
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). 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 ### Building Baritone yourself
You can either build Baritone through a command line or through IntelliJ's UI, information on that can be found [here](SETUP.md#building). 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 ## Placing Baritone in the libraries directory
``/libraries`` is a neat directory in your <a href="https://minecraft.gamepedia.com/.minecraft">Minecraft Installation Directory</a> ``/libraries`` is a neat directory in your <a href="https://minecraft.gamepedia.com/.minecraft">Minecraft Installation Directory</a>
+36
View File
@@ -0,0 +1,36 @@
# Baritone Comms Protocol
## Data Types
| Name | Descriptor | Java |
|------------|-----------------------------------------------------------|-----------------------------|
| coordinate | Big endian 8-byte floating point number | [readDouble], [writeDouble] |
| string | unsigned short (length) followed by UTF-8 character bytes | [readUTF], [writeUTF] |
## Inbound
Allows the server to execute a chat command on behalf of the client's player
### Chat
| Name | Type |
|---------|--------|
| Message | string |
## Outbound
Update the player position with the server
### Status
| Name | Type |
|------|------------|
| X | coordinate |
| Y | coordinate |
| Z | coordinate |
<!-- External links -->
[readUTF]: https://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html#readUTF()
[writeUTF]: https://docs.oracle.com/javase/7/docs/api/java/io/DataOutputStream.html#writeUTF(java.lang.String)
[readDouble]: https://docs.oracle.com/javase/7/docs/api/java/io/DataInputStream.html#readDouble()
[writeDouble]: https://docs.oracle.com/javase/7/docs/api/java/io/DataOutputStream.html#writeDouble(double)
+29 -20
View File
@@ -1,42 +1,51 @@
# Baritone # Baritone
[![Build Status](https://travis-ci.com/cabaletta/baritone.svg?branch=master)](https://travis-ci.com/cabaletta/baritone) [![Build Status](https://travis-ci.com/cabaletta/baritone.svg?branch=master)](https://travis-ci.com/cabaletta/baritone)
[![Release](https://img.shields.io/github/release/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/releases) [![Release](https://img.shields.io/github/release/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/releases)
[![License](https://img.shields.io/badge/license-LGPL--3.0-green.svg)](LICENSE) [![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;utm_campaign=Badge_Grade)
[![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone) [![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone)
[![Known Vulnerabilities](https://snyk.io/test/github/cabaletta/baritone/badge.svg?targetFile=build.gradle)](https://snyk.io/test/github/cabaletta/baritone?targetFile=build.gradle)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues) [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues)
[![Issues](https://img.shields.io/github/issues/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/issues/)
[![GitHub issues-closed](https://img.shields.io/github/issues-closed/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/issues?q=is%3Aissue+is%3Aclosed)
[![Pull Requests](https://img.shields.io/github/issues-pr/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/pulls/)
![Code size](https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg)
![GitHub repo size](https://img.shields.io/github/repo-size/cabaletta/baritone.svg)
[![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2) [![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2)
[![GitHub contributors](https://img.shields.io/github/contributors/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/graphs/contributors/)
[![GitHub commits](https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg)](https://github.com/cabaletta/baritone/commit/)
[![Asuna integration](https://img.shields.io/badge/Asuna%20integration-builder%20branch-brightgreen.svg)](https://github.com/EmotionalLove/Asuna/)
[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.0.0--hotfix--4-green.svg)](https://impactdevelopment.github.io/)
[![KAMI integration](https://img.shields.io/badge/KAMI%20integration-v1.0.0-orange.svg)](https://github.com/zeroeightysix/KAMI/)
[![WWE integration](https://img.shields.io/badge/WWE%20%22integration%22-v1.0.0%3F%3F%20smh%20license%20violations-orange.svg)](https://wweclient.com/)
[![Future integration](https://img.shields.io/badge/Future%20integration-Soon™%3F%3F%3F-red.svg)](https://futureclient.net/)
[![ForgeHax integration](https://img.shields.io/badge/ForgeHax%20integration-Soon™-red.svg)](https://github.com/fr1kin/ForgeHax)
A Minecraft pathfinder bot. A Minecraft pathfinder bot.
Baritone is the pathfinding system used in [Impact](https://impactdevelopment.github.io/) since 4.4. There's a [showcase video](https://www.youtube.com/watch?v=yI8hgW_m6dQ) made by @Adovin#3153 on Baritone's integration into Impact. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a video I made showing off what it can do. 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/), 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 [30x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). 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: Here are some links to help to get started:
- [Features](FEATURES.md) - [Features](FEATURES.md)
- [Setup](SETUP.md)
- [Installation](INSTALL.md) - [Installation](INSTALL.md)
- [Javadocs](https://baritone.leijurv.com/) There's also some useful information down below
# Setup
## Command Line
On Mac OSX and Linux, use `./gradlew` instead of `gradlew`.
Running Baritone:
```
$ gradlew runClient
```
Building Baritone:
```
$ 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 # Chat control
[Defined Here](src/main/java/baritone/utils/ExampleBaritoneControl.java) [Defined Here](src/main/java/baritone/utils/ExampleBaritoneControl.java)
@@ -47,7 +56,7 @@ Quick start example: `thisway 1000` or `goal 70` to set the goal, `path` to actu
``` ```
BaritoneAPI.getSettings().allowSprint.value = true; BaritoneAPI.getSettings().allowSprint.value = true;
BaritoneAPI.getSettings().primaryTimeoutMS.value = 2000L; BaritoneAPI.getSettings().pathTimeoutMS.value = 2000L;
BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalXZ(10000, 20000)); BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAndPath(new GoalXZ(10000, 20000));
``` ```
-79
View File
@@ -1,79 +0,0 @@
# Setup
- Clone or download Baritone
![Image](https://i.imgur.com/kbqBtoN.png)
- If you choose to download, make sure you extract the ZIP archive.
- Follow one of the instruction sets below, based on your preference
## Command Line
On Mac OSX and Linux, use `./gradlew` instead of `gradlew`.
Setting up the Environment:
```
$ gradlew setupDecompWorkspace
$ gradlew --refresh-dependencies
```
Running Baritone:
```
$ gradlew runClient
```
For information on how to build baritone, see [Building Baritone](#building-baritone)
## IntelliJ
- Open the project in IntelliJ as a Gradle project
![Image](https://i.imgur.com/jw7Q6vY.png)
- Run the Gradle tasks `setupDecompWorkspace` then `genIntellijRuns`
![Image](https://i.imgur.com/QEfVvWP.png)
- Refresh the Gradle project (or, to be safe, just restart IntelliJ)
![Image](https://i.imgur.com/3V7EdWr.png)
- Select the "Minecraft Client" launch config
![Image](https://i.imgur.com/1qz2QGV.png)
- Click on ``Edit Configurations...`` from the same dropdown and select the "Minecraft Client" config
![Image](https://i.imgur.com/s4ly0ZF.png)
- In `Edit Configurations...` you need to select `baritone_launch` for `Use classpath of module:`.
![Image](https://i.imgur.com/hrLhG9u.png)
# Building
Make sure that you have properly [setup](#setup) the environment before trying to build it.
## Command Line
```
$ gradlew build
```
## IntelliJ
- Navigate to the gradle tasks on the right tab as follows
![Image](https://i.imgur.com/PE6r9iN.png)
- Right click on **build** and press **Run**
## Artifacts
Building Baritone will result in 3 artifacts created in the ``dist`` directory.
- **API**: Only the non-api packages are obfuscated. This should be used in environments where other mods would like to use Baritone's features.
- **Standalone**: Everything is obfuscated. This should be used in environments where there are no other mods present that would like to use Baritone's features.
- **Unoptimized**: Nothing is obfuscated. This shouldn't be used ever in production.
## More Info
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"`).
+12 -10
View File
@@ -48,13 +48,22 @@ apply plugin: 'org.spongepowered.mixin'
sourceCompatibility = targetCompatibility = '1.8' sourceCompatibility = targetCompatibility = '1.8'
compileJava { compileJava {
sourceCompatibility = targetCompatibility = '1.8' sourceCompatibility = targetCompatibility = '1.8'
options.encoding = "UTF-8" // allow emoji in comments :^)
} }
sourceSets { sourceSets {
comms {}
main {
compileClasspath += comms.compileClasspath + comms.output
}
launch { launch {
compileClasspath += main.compileClasspath + main.runtimeClasspath + main.output compileClasspath += main.compileClasspath + main.runtimeClasspath + main.output
} }
tenor {
compileClasspath += comms.compileClasspath + comms.output
}
main {
compileClasspath += tenor.compileClasspath + tenor.output
}
} }
minecraft { minecraft {
@@ -99,16 +108,8 @@ mixin {
add sourceSets.launch, 'mixins.baritone.refmap.json' add sourceSets.launch, 'mixins.baritone.refmap.json'
} }
javadoc {
options.addStringOption('Xwerror', '-quiet') // makes the build fail on travis when there is a javadoc error
options.linkSource true
options.encoding "UTF-8" // allow emoji in comments :^)
source += sourceSets.api.allJava
classpath += sourceSets.api.compileClasspath
}
jar { jar {
from sourceSets.launch.output, sourceSets.api.output from sourceSets.comms.output, sourceSets.launch.output, sourceSets.api.output
preserveFileTimestamps = false preserveFileTimestamps = false
reproducibleFileOrder = true reproducibleFileOrder = true
} }
@@ -116,6 +117,7 @@ jar {
task proguard(type: ProguardTask) { task proguard(type: ProguardTask) {
url 'https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip' url 'https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip'
extract 'proguard6.0.3/lib/proguard.jar' extract 'proguard6.0.3/lib/proguard.jar'
versionManifest 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
} }
task createDist(type: CreateDistTask, dependsOn: proguard) task createDist(type: CreateDistTask, dependsOn: proguard)
@@ -18,26 +18,21 @@
package baritone.gradle.task; package baritone.gradle.task;
import baritone.gradle.util.Determinizer; import baritone.gradle.util.Determinizer;
import baritone.gradle.util.MappingType; import com.google.gson.*;
import baritone.gradle.util.ReobfWrapper;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.Dependency;
import org.gradle.api.internal.plugins.DefaultConvention;
import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.Pair; import org.gradle.internal.Pair;
import java.io.*; import java.io.*;
import java.lang.reflect.Field;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
@@ -57,6 +52,10 @@ public class ProguardTask extends BaritoneGradleTask {
@Input @Input
private String extract; private String extract;
@Input
private String versionManifest;
private Map<String, String> versionDownloadMap;
private List<String> requiredLibraries; private List<String> requiredLibraries;
@TaskAction @TaskAction
@@ -68,6 +67,7 @@ public class ProguardTask extends BaritoneGradleTask {
downloadProguard(); downloadProguard();
extractProguard(); extractProguard();
generateConfigs(); generateConfigs();
downloadVersionManifest();
acquireDependencies(); acquireDependencies();
proguardApi(); proguardApi();
proguardStandalone(); proguardStandalone();
@@ -132,6 +132,20 @@ public class ProguardTask extends BaritoneGradleTask {
}); });
} }
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 { private void acquireDependencies() throws Exception {
// Create a map of all of the dependencies that we are able to access in this project // Create a map of all of the dependencies that we are able to access in this project
@@ -149,13 +163,15 @@ public class ProguardTask extends BaritoneGradleTask {
// Iterate the required libraries to copy them to tempLibraries // Iterate the required libraries to copy them to tempLibraries
for (String lib : this.requiredLibraries) { for (String lib : this.requiredLibraries) {
// copy from the forgegradle cache // Download the version jar from the URL acquired from the version manifest
if (lib.equals("minecraft")) { if (lib.startsWith("minecraft")) {
Path cachedJar = getMinecraftJar(); String version = lib.split("-")[1];
Path inTempDir = getTemporaryFile("tempLibraries/minecraft.jar"); Path versionJar = getTemporaryFile("tempLibraries/" + lib + ".jar");
// TODO: maybe try not to copy every time if (!Files.exists(versionJar)) {
Files.copy(cachedJar, inTempDir, REPLACE_EXISTING); 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; continue;
} }
@@ -179,89 +195,6 @@ public class ProguardTask extends BaritoneGradleTask {
} }
} }
// a bunch of epic stuff to get the path to the cached jar
private Path getMinecraftJar() throws Exception {
MappingType mappingType;
try {
mappingType = getMappingType();
} catch (Exception e) {
System.err.println("Failed to get mapping type, assuming NOTCH.");
mappingType = MappingType.NOTCH;
}
String suffix;
switch (mappingType) {
case NOTCH:
suffix = "";
break;
case SEARGE:
suffix = "-srgBin";
break;
case CUSTOM:
throw new IllegalStateException("Custom mappings not supported!");
default:
throw new IllegalStateException("Unknown mapping type: " + mappingType);
}
DefaultConvention convention = (DefaultConvention) this.getProject().getConvention();
Object extension = convention.getAsMap().get("minecraft");
Objects.requireNonNull(extension);
// for some reason cant use Class.forName
Class<?> class_baseExtension = extension.getClass().getSuperclass().getSuperclass().getSuperclass(); // <-- cursed
Field f_replacer = class_baseExtension.getDeclaredField("replacer");
f_replacer.setAccessible(true);
Object replacer = f_replacer.get(extension);
Class<?> class_replacementProvider = replacer.getClass();
Field replacement_replaceMap = class_replacementProvider.getDeclaredField("replaceMap");
replacement_replaceMap.setAccessible(true);
Map<String, Object> replacements = (Map) replacement_replaceMap.get(replacer);
String cacheDir = replacements.get("CACHE_DIR").toString() + "/net/minecraft";
String mcVersion = replacements.get("MC_VERSION").toString();
String mcpInsert = replacements.get("MAPPING_CHANNEL").toString() + "/" + replacements.get("MAPPING_VERSION").toString();
String fullJarName = "minecraft-" + mcVersion + suffix + ".jar";
String baseDir = String.format("%s/minecraft/%s/", cacheDir, mcVersion);
String jarPath;
if (mappingType == MappingType.SEARGE) {
jarPath = String.format("%s/%s/%s", baseDir, mcpInsert, fullJarName);
} else {
jarPath = baseDir + fullJarName;
}
jarPath = jarPath
.replace("/", File.separator)
.replace("\\", File.separator); // hecking regex
return new File(jarPath).toPath();
}
// throws IllegalStateException if mapping type is ambiguous or it fails to find it
private MappingType getMappingType() {
// if it fails to find this then its probably a forgegradle version problem
Set<Object> reobf = (NamedDomainObjectContainer<Object>) this.getProject().getExtensions().getByName("reobf");
List<MappingType> mappingTypes = getUsedMappingTypes(reobf);
long mappingTypesUsed = mappingTypes.size();
if (mappingTypesUsed == 0) {
throw new IllegalStateException("Failed to find mapping type (no jar task?)");
}
if (mappingTypesUsed > 1) {
throw new IllegalStateException("Ambiguous mapping type (multiple jars with different mapping types?)");
}
return mappingTypes.get(0);
}
private List<MappingType> getUsedMappingTypes(Set<Object> reobf) {
return reobf.stream()
.map(ReobfWrapper::new)
.map(ReobfWrapper::getMappingType)
.distinct()
.collect(Collectors.toList());
}
private void proguardApi() throws Exception { private void proguardApi() throws Exception {
runProguard(getTemporaryFile(PROGUARD_API_CONFIG)); runProguard(getTemporaryFile(PROGUARD_API_CONFIG));
Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString()); Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString());
@@ -286,6 +219,10 @@ public class ProguardTask extends BaritoneGradleTask {
this.extract = extract; this.extract = extract;
} }
public void setVersionManifest(String versionManifest) {
this.versionManifest = versionManifest;
}
private void runProguard(Path config) throws Exception { private void runProguard(Path config) throws Exception {
// Delete the existing proguard output file. Proguard probably handles this already, but why not do it ourselves // Delete the existing proguard output file. Proguard probably handles this already, but why not do it ourselves
if (Files.exists(this.proguardOut)) { if (Files.exists(this.proguardOut)) {
@@ -315,7 +252,7 @@ public class ProguardTask extends BaritoneGradleTask {
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
System.out.println(line); System.out.println(line);
} }
} catch (Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
}).start(); }).start();
@@ -1,63 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.gradle.util;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* All credits go to AsmLibGradle and its contributors.
*
* @see <a href="https://github.com/pozzed/AsmLibGradle/blob/8f917dbc3939eab7a3d9daf54d9d285fdf34f4b2/src/main/java/net/futureclient/asmlib/forgegradle/ReobfWrapper.java">Original Source</a>
*/
public class ReobfWrapper {
private final Object instance;
private final Class<?> type;
public ReobfWrapper(Object instance) {
this.instance = instance;
Objects.requireNonNull(instance);
this.type = instance.getClass();
}
public String getName() {
try {
Field nameField = type.getDeclaredField("name");
nameField.setAccessible(true);
return (String) nameField.get(this.instance);
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}
public MappingType getMappingType() {
try {
Field enumField = type.getDeclaredField("mappingType");
enumField.setAccessible(true);
Enum<?> aEnum = (Enum<?>) enumField.get(this.instance);
MappingType mappingType = MappingType.values()[aEnum.ordinal()];
if (!aEnum.name().equals(mappingType.name())) {
throw new IllegalStateException("ForgeGradle ReobfMappingType is not equivalent to MappingType (version error?)");
}
return mappingType;
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}
}
+1 -2
View File
@@ -31,8 +31,7 @@
# copy all necessary libraries into tempLibraries to build # copy all necessary libraries into tempLibraries to build
# The correct jar will be copied from the forgegradle cache based on the mapping type being compiled with -libraryjars 'tempLibraries/minecraft-1.12.2.jar'
-libraryjars 'tempLibraries/minecraft.jar'
-libraryjars 'tempLibraries/SimpleTweaker-1.2.jar' -libraryjars 'tempLibraries/SimpleTweaker-1.2.jar'
+9 -2
View File
@@ -18,6 +18,7 @@
package baritone.api; package baritone.api;
import baritone.api.behavior.ILookBehavior; import baritone.api.behavior.ILookBehavior;
import baritone.api.behavior.IMemoryBehavior;
import baritone.api.behavior.IPathingBehavior; import baritone.api.behavior.IPathingBehavior;
import baritone.api.cache.IWorldProvider; import baritone.api.cache.IWorldProvider;
import baritone.api.event.listener.IEventBus; import baritone.api.event.listener.IEventBus;
@@ -47,12 +48,20 @@ public interface IBaritone {
*/ */
ILookBehavior getLookBehavior(); ILookBehavior getLookBehavior();
/**
* @return The {@link IMemoryBehavior} instance
* @see IMemoryBehavior
*/
IMemoryBehavior getMemoryBehavior();
/** /**
* @return The {@link IMineProcess} instance * @return The {@link IMineProcess} instance
* @see IMineProcess * @see IMineProcess
*/ */
IMineProcess getMineProcess(); IMineProcess getMineProcess();
IPathingControlManager getPathingControlManager();
/** /**
* @return The {@link IPathingBehavior} instance * @return The {@link IPathingBehavior} instance
* @see IPathingBehavior * @see IPathingBehavior
@@ -65,8 +74,6 @@ public interface IBaritone {
*/ */
IWorldProvider getWorldProvider(); IWorldProvider getWorldProvider();
IPathingControlManager getPathingControlManager();
IInputOverrideHandler getInputOverrideHandler(); IInputOverrideHandler getInputOverrideHandler();
ICustomGoalProcess getCustomGoalProcess(); ICustomGoalProcess getCustomGoalProcess();
+97 -182
View File
@@ -33,67 +33,52 @@ import java.util.function.Consumer;
* *
* @author leijurv * @author leijurv
*/ */
public final class Settings { public class Settings {
/** /**
* Allow Baritone to break blocks * Allow Baritone to break blocks
*/ */
public final Setting<Boolean> allowBreak = new Setting<>(true); public Setting<Boolean> allowBreak = new Setting<>(true);
/** /**
* Allow Baritone to sprint * Allow Baritone to sprint
*/ */
public final Setting<Boolean> allowSprint = new Setting<>(true); public Setting<Boolean> allowSprint = new Setting<>(true);
/** /**
* Allow Baritone to place blocks * Allow Baritone to place blocks
*/ */
public final Setting<Boolean> allowPlace = new Setting<>(true); public Setting<Boolean> allowPlace = new Setting<>(true);
/**
* Allow Baritone to move items in your inventory to your hotbar
*/
public final Setting<Boolean> allowInventory = new Setting<>(false);
/** /**
* It doesn't actually take twenty ticks to place a block, this cost is so high * It doesn't actually take twenty ticks to place a block, this cost is so high
* because we want to generally conserve blocks which might be limited * because we want to generally conserve blocks which might be limited
*/ */
public final Setting<Double> blockPlacementPenalty = new Setting<>(20D); public Setting<Double> blockPlacementPenalty = new Setting<>(20D);
/** /**
* This is just a tiebreaker to make it less likely to break blocks if it can avoid it. * 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 * 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. * it will take an otherwise equivalent route that doesn't require it to put out fire.
*/ */
public final Setting<Double> blockBreakAdditionalPenalty = new Setting<>(2D); public Setting<Double> blockBreakAdditionalPenalty = new Setting<>(2D);
/**
* Additional penalty for hitting the space bar (ascend, pillar, or parkour) because it uses hunger
*/
public final Setting<Double> jumpPenalty = new Setting<>(2D);
/**
* Walking on water uses up hunger really quick, so penalize it
*/
public final Setting<Double> walkOnWaterOnePenalty = new Setting<>(5D);
/** /**
* Allow Baritone to fall arbitrary distances and place a water bucket beneath it. * Allow Baritone to fall arbitrary distances and place a water bucket beneath it.
* Reliability: questionable. * Reliability: questionable.
*/ */
public final Setting<Boolean> allowWaterBucketFall = new Setting<>(true); public Setting<Boolean> allowWaterBucketFall = new Setting<>(true);
/** /**
* Allow Baritone to assume it can walk on still water just like any other block. * Allow Baritone to assume it can walk on still water just like any other block.
* This functionality is assumed to be provided by a separate library that might have imported Baritone. * This functionality is assumed to be provided by a separate library that might have imported Baritone.
*/ */
public final Setting<Boolean> assumeWalkOnWater = new Setting<>(false); public Setting<Boolean> assumeWalkOnWater = new Setting<>(false);
/** /**
* Assume step functionality; don't jump on an Ascend. * Assume step functionality; don't jump on an Ascend.
*/ */
public final Setting<Boolean> assumeStep = new Setting<>(false); public Setting<Boolean> assumeStep = new Setting<>(false);
/** /**
* Assume safe walk functionality; don't sneak on a backplace traverse. * Assume safe walk functionality; don't sneak on a backplace traverse.
@@ -102,28 +87,12 @@ public final class Settings {
* it won't sneak right click, it'll just right click, which means it'll open the chest instead of placing * it won't sneak right click, it'll just right click, which means it'll open the chest instead of placing
* against it. That's why this defaults to off. * against it. That's why this defaults to off.
*/ */
public final Setting<Boolean> assumeSafeWalk = new Setting<>(false); public Setting<Boolean> assumeSafeWalk = new Setting<>(false);
/**
* If true, parkour is allowed to make jumps when standing on blocks at the maximum height, so player feet is y=256
* <p>
* Defaults to false because this fails on constantiam
*/
public final Setting<Boolean> allowJumpAt256 = new Setting<>(false);
/**
* Allow descending diagonally
* <p>
* Safer than allowParkour yet still slightly unsafe, can make contact with unchecked adjacent blocks, so it's unsafe in the nether.
* <p>
* For a generic "take some risks" mode I'd turn on this one, parkour, and parkour place.
*/
public final Setting<Boolean> allowDiagonalDescend = new Setting<>(false);
/** /**
* Blocks that Baritone is allowed to place (as throwaway, for sneak bridging, pillaring, etc.) * Blocks that Baritone is allowed to place (as throwaway, for sneak bridging, pillaring, etc.)
*/ */
public final Setting<List<Item>> acceptableThrowawayItems = new Setting<>(new ArrayList<>(Arrays.asList( public Setting<List<Item>> acceptableThrowawayItems = new Setting<>(new ArrayList<>(Arrays.asList(
Item.getItemFromBlock(Blocks.DIRT), Item.getItemFromBlock(Blocks.DIRT),
Item.getItemFromBlock(Blocks.COBBLESTONE), Item.getItemFromBlock(Blocks.COBBLESTONE),
Item.getItemFromBlock(Blocks.NETHERRACK) Item.getItemFromBlock(Blocks.NETHERRACK)
@@ -132,37 +101,31 @@ public final class Settings {
/** /**
* Enables some more advanced vine features. They're honestly just gimmicks and won't ever be needed in real * Enables some more advanced vine features. They're honestly just gimmicks and won't ever be needed in real
* pathing scenarios. And they can cause Baritone to get trapped indefinitely in a strange scenario. * pathing scenarios. And they can cause Baritone to get trapped indefinitely in a strange scenario.
* <p>
* Never turn this on lol
*/ */
public final Setting<Boolean> allowVines = new Setting<>(false); public Setting<Boolean> allowVines = new Setting<>(false);
/** /**
* Slab behavior is complicated, disable this for higher path reliability. Leave enabled if you have bottom slabs * Slab behavior is complicated, disable this for higher path reliability. Leave enabled if you have bottom slabs
* everywhere in your base. * everywhere in your base.
*/ */
public final Setting<Boolean> allowWalkOnBottomSlab = new Setting<>(true); public Setting<Boolean> allowWalkOnBottomSlab = new Setting<>(true);
/** /**
* You know what it is * You know what it is
* <p> * <p>
* But it's very unreliable and falls off when cornering like all the time so. * But it's very unreliable and falls off when cornering like all the time so.
* <p>
* It also overshoots the landing pretty much always (making contact with the next block over), so be careful
*/ */
public final Setting<Boolean> allowParkour = new Setting<>(false); public Setting<Boolean> allowParkour = new Setting<>(false);
/** /**
* Actually pretty reliable. * Like parkour, but even more unreliable!
* <p>
* Doesn't make it any more dangerous compared to just normal allowParkour th
*/ */
public final Setting<Boolean> allowParkourPlace = new Setting<>(false); public Setting<Boolean> allowParkourPlace = new Setting<>(false);
/** /**
* For example, if you have Mining Fatigue or Haste, adjust the costs of breaking blocks accordingly. * For example, if you have Mining Fatigue or Haste, adjust the costs of breaking blocks accordingly.
*/ */
public final Setting<Boolean> considerPotionEffects = new Setting<>(true); public Setting<Boolean> considerPotionEffects = new Setting<>(true);
/** /**
* This is the big A* setting. * This is the big A* setting.
@@ -179,137 +142,95 @@ public final class Settings {
* <p> * <p>
* Finding the optimal path is worth it, so it's the default. * Finding the optimal path is worth it, so it's the default.
*/ */
public final Setting<Double> costHeuristic = new Setting<>(3.563); public Setting<Double> costHeuristic = new Setting<>(3.5D);
// a bunch of obscure internal A* settings that you probably don't want to change // a bunch of obscure internal A* settings that you probably don't want to change
/** /**
* The maximum number of times it will fetch outside loaded or cached chunks before assuming that * The maximum number of times it will fetch outside loaded or cached chunks before assuming that
* pathing has reached the end of the known area, and should therefore stop. * pathing has reached the end of the known area, and should therefore stop.
*/ */
public final Setting<Integer> pathingMaxChunkBorderFetch = new Setting<>(50); public Setting<Integer> pathingMaxChunkBorderFetch = new Setting<>(50);
/** /**
* Set to 1.0 to effectively disable this feature * Set to 1.0 to effectively disable this feature
* *
* @see <a href="https://github.com/cabaletta/baritone/issues/18">Issue #18</a> * @see <a href="https://github.com/cabaletta/baritone/issues/18">Issue #18</a>
*/ */
public final Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.5); public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.5);
/**
* Toggle the following 4 settings
* <p>
* They have a noticeable performance impact, so they default off
* <p>
* Specifically, building up the avoidance map on the main thread before pathing starts actually takes a noticeable
* amount of time, especially when there are a lot of mobs around, and your game jitters for like 200ms while doing so
*/
public final Setting<Boolean> avoidance = new Setting<>(false);
/**
* Set to 1.0 to effectively disable this feature
* <p>
* Set below 1.0 to go out of your way to walk near mob spawners
*/
public final Setting<Double> mobSpawnerAvoidanceCoefficient = new Setting<>(2.0);
public final Setting<Integer> mobSpawnerAvoidanceRadius = new Setting<>(16);
/**
* Set to 1.0 to effectively disable this feature
* <p>
* Set below 1.0 to go out of your way to walk near mobs
*/
public final Setting<Double> mobAvoidanceCoefficient = new Setting<>(1.5);
public final Setting<Integer> mobAvoidanceRadius = new Setting<>(8);
/**
* When running a goto towards a container block (chest, ender chest, furnace, etc),
* right click and open it once you arrive.
*/
public final Setting<Boolean> rightClickContainerOnArrival = new Setting<>(true);
/**
* When running a goto towards a nether portal block, walk all the way into the portal
* instead of stopping one block before.
*/
public final Setting<Boolean> enterPortal = new Setting<>(true);
/** /**
* Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies, * Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies,
* and there's no point. * and there's no point.
*/ */
public final Setting<Boolean> minimumImprovementRepropagation = new Setting<>(true); public Setting<Boolean> minimumImprovementRepropagation = new Setting<>(true);
/** /**
* After calculating a path (potentially through cached chunks), artificially cut it off to just the part that is * After calculating a path (potentially through cached chunks), artificially cut it off to just the part that is
* entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified. * entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified.
* <p>
* This is much safer to leave off now, and makes pathing more efficient. More explanation in the issue.
* *
* @see <a href="https://github.com/cabaletta/baritone/issues/114">Issue #114</a> * @see <a href="https://github.com/cabaletta/baritone/issues/144">Issue #144</a>
*/ */
public final Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(false); public Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(false);
/** /**
* If a movement's cost increases by more than this amount between calculation and execution (due to changes * If a movement's cost increases by more than this amount between calculation and execution (due to changes
* in the environment / world), cancel and recalculate * in the environment / world), cancel and recalculate
*/ */
public final Setting<Double> maxCostIncrease = new Setting<>(10D); public Setting<Double> maxCostIncrease = new Setting<>(10D);
/** /**
* Stop 5 movements before anything that made the path COST_INF. * Stop 5 movements before anything that made the path COST_INF.
* For example, if lava has spread across the path, don't walk right up to it then recalculate, it might * For example, if lava has spread across the path, don't walk right up to it then recalculate, it might
* still be spreading lol * still be spreading lol
*/ */
public final Setting<Integer> costVerificationLookahead = new Setting<>(5); public Setting<Integer> costVerificationLookahead = new Setting<>(5);
/** /**
* Static cutoff factor. 0.9 means cut off the last 10% of all paths, regardless of chunk load state * Static cutoff factor. 0.9 means cut off the last 10% of all paths, regardless of chunk load state
*/ */
public final Setting<Double> pathCutoffFactor = new Setting<>(0.9); public Setting<Double> pathCutoffFactor = new Setting<>(0.9);
/** /**
* Only apply static cutoff for paths of at least this length (in terms of number of movements) * Only apply static cutoff for paths of at least this length (in terms of number of movements)
*/ */
public final Setting<Integer> pathCutoffMinimumLength = new Setting<>(30); public Setting<Integer> pathCutoffMinimumLength = new Setting<>(30);
/** /**
* Start planning the next path once the remaining movements tick estimates sum up to less than this value * Start planning the next path once the remaining movements tick estimates sum up to less than this value
*/ */
public final Setting<Integer> planningTickLookAhead = new Setting<>(150); public Setting<Integer> planningTickLookAhead = new Setting<>(150);
/** /**
* Default size of the Long2ObjectOpenHashMap used in pathing * Default size of the Long2ObjectOpenHashMap used in pathing
*/ */
public final Setting<Integer> pathingMapDefaultSize = new Setting<>(1024); public Setting<Integer> pathingMapDefaultSize = new Setting<>(1024);
/** /**
* Load factor coefficient for the Long2ObjectOpenHashMap used in pathing * Load factor coefficient for the Long2ObjectOpenHashMap used in pathing
* <p> * <p>
* Decrease for faster map operations, but higher memory usage * Decrease for faster map operations, but higher memory usage
*/ */
public final Setting<Float> pathingMapLoadFactor = new Setting<>(0.75f); public Setting<Float> pathingMapLoadFactor = new Setting<>(0.75f);
/** /**
* How far are you allowed to fall onto solid ground (without a water bucket)? * How far are you allowed to fall onto solid ground (without a water bucket)?
* 3 won't deal any damage. But if you just want to get down the mountain quickly and you have * 3 won't deal any damage. But if you just want to get down the mountain quickly and you have
* Feather Falling IV, you might set it a bit higher, like 4 or 5. * Feather Falling IV, you might set it a bit higher, like 4 or 5.
*/ */
public final Setting<Integer> maxFallHeightNoWater = new Setting<>(3); public Setting<Integer> maxFallHeightNoWater = new Setting<>(3);
/** /**
* How far are you allowed to fall onto solid ground (with a water bucket)? * How far are you allowed to fall onto solid ground (with a water bucket)?
* It's not that reliable, so I've set it below what would kill an unarmored player (23) * It's not that reliable, so I've set it below what would kill an unarmored player (23)
*/ */
public final Setting<Integer> maxFallHeightBucket = new Setting<>(20); public Setting<Integer> maxFallHeightBucket = new Setting<>(20);
/** /**
* Is it okay to sprint through a descend followed by a diagonal? * Is it okay to sprint through a descend followed by a diagonal?
* The player overshoots the landing, but not enough to fall off. And the diagonal ensures that there isn't * The player overshoots the landing, but not enough to fall off. And the diagonal ensures that there isn't
* lava or anything that's !canWalkInto in that space, so it's technically safe, just a little sketchy. * lava or anything that's !canWalkInto in that space, so it's technically safe, just a little sketchy.
*/ */
public final Setting<Boolean> allowOvershootDiagonalDescend = new Setting<>(true); public Setting<Boolean> allowOvershootDiagonalDescend = new Setting<>(true);
/** /**
* If your goal is a GoalBlock in an unloaded chunk, assume it's far enough away that the Y coord * If your goal is a GoalBlock in an unloaded chunk, assume it's far enough away that the Y coord
@@ -318,133 +239,125 @@ public final class Settings {
* of considering the Y coord. The reasoning is that if your X and Z are 10,000 blocks away, * of considering the Y coord. The reasoning is that if your X and Z are 10,000 blocks away,
* your Y coordinate's accuracy doesn't matter at all until you get much much closer. * your Y coordinate's accuracy doesn't matter at all until you get much much closer.
*/ */
public final Setting<Boolean> simplifyUnloadedYCoord = new Setting<>(true); public Setting<Boolean> simplifyUnloadedYCoord = new Setting<>(true);
/** /**
* If a movement takes this many ticks more than its initial cost estimate, cancel it * If a movement takes this many ticks more than its initial cost estimate, cancel it
*/ */
public final Setting<Integer> movementTimeoutTicks = new Setting<>(100); public Setting<Integer> movementTimeoutTicks = new Setting<>(100);
/** /**
* Pathing ends after this amount of time, but only if a path has been found * Pathing ends after this amount of time, but only if a path has been found
* <p> * <p>
* If no valid path (length above the minimum) has been found, pathing continues up until the failure timeout * If no valid path (length above the minimum) has been found, pathing continues up until the failure timeout
*/ */
public final Setting<Long> primaryTimeoutMS = new Setting<>(500L); public Setting<Long> primaryTimeoutMS = new Setting<>(500L);
/** /**
* Pathing can never take longer than this, even if that means failing to find any path at all * Pathing can never take longer than this, even if that means failing to find any path at all
*/ */
public final Setting<Long> failureTimeoutMS = new Setting<>(2000L); public Setting<Long> failureTimeoutMS = new Setting<>(2000L);
/** /**
* Planning ahead while executing a segment ends after this amount of time, but only if a path has been found * Planning ahead while executing a segment ends after this amount of time, but only if a path has been found
* <p> * <p>
* If no valid path (length above the minimum) has been found, pathing continues up until the failure timeout * If no valid path (length above the minimum) has been found, pathing continues up until the failure timeout
*/ */
public final Setting<Long> planAheadPrimaryTimeoutMS = new Setting<>(4000L); public Setting<Long> planAheadPrimaryTimeoutMS = new Setting<>(4000L);
/** /**
* Planning ahead while executing a segment can never take longer than this, even if that means failing to find any path at all * Planning ahead while executing a segment can never take longer than this, even if that means failing to find any path at all
*/ */
public final Setting<Long> planAheadFailureTimeoutMS = new Setting<>(5000L); public Setting<Long> planAheadFailureTimeoutMS = new Setting<>(5000L);
/** /**
* For debugging, consider nodes much much slower * For debugging, consider nodes much much slower
*/ */
public final Setting<Boolean> slowPath = new Setting<>(false); public Setting<Boolean> slowPath = new Setting<>(false);
/** /**
* Milliseconds between each node * Milliseconds between each node
*/ */
public final Setting<Long> slowPathTimeDelayMS = new Setting<>(100L); public Setting<Long> slowPathTimeDelayMS = new Setting<>(100L);
/** /**
* The alternative timeout number when slowPath is on * The alternative timeout number when slowPath is on
*/ */
public final Setting<Long> slowPathTimeoutMS = new Setting<>(40000L); public Setting<Long> slowPathTimeoutMS = new Setting<>(40000L);
/** /**
* The big one. Download all chunks in simplified 2-bit format and save them for better very-long-distance pathing. * The big one. Download all chunks in simplified 2-bit format and save them for better very-long-distance pathing.
*/ */
public final Setting<Boolean> chunkCaching = new Setting<>(true); public Setting<Boolean> chunkCaching = new Setting<>(true);
/** /**
* On save, delete from RAM any cached regions that are more than 1024 blocks away from the player * On save, delete from RAM any cached regions that are more than 1024 blocks away from the player
* <p> * <p>
* Temporarily disabled * Temporarily disabled, see issue #248
*
* @see <a href="https://github.com/cabaletta/baritone/issues/248">Issue #248</a>
*/ */
public final Setting<Boolean> pruneRegionsFromRAM = new Setting<>(false); public Setting<Boolean> pruneRegionsFromRAM = new Setting<>(false);
/** /**
* Print all the debug messages to chat * Print all the debug messages to chat
*/ */
public final Setting<Boolean> chatDebug = new Setting<>(true); public Setting<Boolean> chatDebug = new Setting<>(true);
/** /**
* Allow chat based control of Baritone. Most likely should be disabled when Baritone is imported for use in * Allow chat based control of Baritone. Most likely should be disabled when Baritone is imported for use in
* something else * something else
*/ */
public final Setting<Boolean> chatControl = new Setting<>(true); public Setting<Boolean> chatControl = new Setting<>(true);
/** /**
* A second override over chatControl to force it on * A second override over chatControl to force it on
*/ */
public final Setting<Boolean> removePrefix = new Setting<>(false); public Setting<Boolean> removePrefix = new Setting<>(false);
/** /**
* Render the path * Render the path
*/ */
public final Setting<Boolean> renderPath = new Setting<>(true); public Setting<Boolean> renderPath = new Setting<>(true);
/** /**
* Render the goal * Render the goal
*/ */
public final Setting<Boolean> renderGoal = new Setting<>(true); public Setting<Boolean> renderGoal = new Setting<>(true);
/** /**
* Ignore depth when rendering the goal * Ignore depth when rendering the goal
*/ */
public final Setting<Boolean> renderGoalIgnoreDepth = new Setting<>(true); public Setting<Boolean> renderGoalIgnoreDepth = new Setting<>(true);
/**
* Renders X/Z type Goals with the vanilla beacon beam effect. Combining this with
* {@link #renderGoalIgnoreDepth} will cause strange render clipping.
*/
public final Setting<Boolean> renderGoalXZBeacon = new Setting<>(false);
/** /**
* Ignore depth when rendering the selection boxes (to break, to place, to walk into) * Ignore depth when rendering the selection boxes (to break, to place, to walk into)
*/ */
public final Setting<Boolean> renderSelectionBoxesIgnoreDepth = new Setting<>(true); public Setting<Boolean> renderSelectionBoxesIgnoreDepth = new Setting<>(true);
/** /**
* Ignore depth when rendering the path * Ignore depth when rendering the path
*/ */
public final Setting<Boolean> renderPathIgnoreDepth = new Setting<>(true); public Setting<Boolean> renderPathIgnoreDepth = new Setting<>(true);
/** /**
* Line width of the path when rendered, in pixels * Line width of the path when rendered, in pixels
*/ */
public final Setting<Float> pathRenderLineWidthPixels = new Setting<>(5F); public Setting<Float> pathRenderLineWidthPixels = new Setting<>(5F);
/** /**
* Line width of the goal when rendered, in pixels * Line width of the goal when rendered, in pixels
*/ */
public final Setting<Float> goalRenderLineWidthPixels = new Setting<>(3F); public Setting<Float> goalRenderLineWidthPixels = new Setting<>(3F);
/** /**
* Start fading out the path at 20 movements ahead, and stop rendering it entirely 30 movements ahead. * Start fading out the path at 20 movements ahead, and stop rendering it entirely 30 movements ahead.
* Improves FPS. * Improves FPS.
*/ */
public final Setting<Boolean> fadePath = new Setting<>(false); public Setting<Boolean> fadePath = new Setting<>(false);
/** /**
* Move without having to force the client-sided rotations * Move without having to force the client-sided rotations
*/ */
public final Setting<Boolean> freeLook = new Setting<>(true); public Setting<Boolean> freeLook = new Setting<>(true);
/** /**
* Will cause some minor behavioral differences to ensure that Baritone works on anticheats. * Will cause some minor behavioral differences to ensure that Baritone works on anticheats.
@@ -452,43 +365,52 @@ public final class Settings {
* At the moment this will silently set the player's rotations when using freeLook so you're not sprinting in * At the moment this will silently set the player's rotations when using freeLook so you're not sprinting in
* directions other than forward, which is picken up by more "advanced" anticheats like AAC, but not NCP. * directions other than forward, which is picken up by more "advanced" anticheats like AAC, but not NCP.
*/ */
public final Setting<Boolean> antiCheatCompatibility = new Setting<>(true); public Setting<Boolean> antiCheatCompatibility = new Setting<>(true);
/** /**
* Exclusively use cached chunks for pathing * Exclusively use cached chunks for pathing
*/ */
public final Setting<Boolean> pathThroughCachedOnly = new Setting<>(false); public Setting<Boolean> pathThroughCachedOnly = new Setting<>(false);
/** /**
* Whether or not to use the "#" command prefix * Whether or not to use the "#" command prefix
*/ */
public final Setting<Boolean> prefix = new Setting<>(false); public Setting<Boolean> prefix = new Setting<>(false);
/**
* {@code true}: can mine blocks when in inventory, chat, or tabbed away in ESC menu
* <p>
* {@code false}: works on cosmic prisons
* <p>
* LOL
*/
public Setting<Boolean> leftClickWorkaround = new Setting<>(true);
/** /**
* Don't stop walking forward when you need to break blocks in your way * Don't stop walking forward when you need to break blocks in your way
*/ */
public final Setting<Boolean> walkWhileBreaking = new Setting<>(true); public Setting<Boolean> walkWhileBreaking = new Setting<>(true);
/** /**
* If we are more than 300 movements into the current path, discard the oldest segments, as they are no longer useful * If we are more than 500 movements into the current path, discard the oldest segments, as they are no longer useful
*/ */
public final Setting<Integer> maxPathHistoryLength = new Setting<>(300); public Setting<Integer> maxPathHistoryLength = new Setting<>(300);
/** /**
* If the current path is too long, cut off this many movements from the beginning. * If the current path is too long, cut off this many movements from the beginning.
*/ */
public final Setting<Integer> pathHistoryCutoffAmount = new Setting<>(50); public Setting<Integer> pathHistoryCutoffAmount = new Setting<>(50);
/** /**
* Rescan for the goal once every 5 ticks. * Rescan for the goal once every 5 ticks.
* Set to 0 to disable. * Set to 0 to disable.
*/ */
public final Setting<Integer> mineGoalUpdateInterval = new Setting<>(5); public Setting<Integer> 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)? * While mining, should it also consider dropped items of the correct type as a pathing destination (as well as ore blocks)?
*/ */
public final Setting<Boolean> mineScanDroppedItems = new Setting<>(true); public Setting<Boolean> 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. * Cancel the current path if the goal has changed, and the path originally ended in the goal but doesn't anymore.
@@ -503,54 +425,54 @@ public final class Settings {
* <p> * <p>
* Also on cosmic prisons this should be set to true since you don't actually mine the ore it just gets replaced with stone. * Also on cosmic prisons this should be set to true since you don't actually mine the ore it just gets replaced with stone.
*/ */
public final Setting<Boolean> cancelOnGoalInvalidation = new Setting<>(true); public Setting<Boolean> cancelOnGoalInvalidation = new Setting<>(true);
/** /**
* The "axis" command (aka GoalAxis) will go to a axis, or diagonal axis, at this Y level. * The "axis" command (aka GoalAxis) will go to a axis, or diagonal axis, at this Y level.
*/ */
public final Setting<Integer> axisHeight = new Setting<>(120); public Setting<Integer> axisHeight = new Setting<>(120);
/** /**
* Disallow MineBehavior from using X-Ray to see where the ores are. Turn this option on to force it to mine "legit" * 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 * 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 on * couldn't. If you don't want it to look like you're X-Raying, turn this off
*/ */
public final Setting<Boolean> legitMine = new Setting<>(false); public Setting<Boolean> legitMine = new Setting<>(false);
/** /**
* What Y level to go to for legit strip mining * What Y level to go to for legit strip mining
*/ */
public final Setting<Integer> legitMineYLevel = new Setting<>(11); public Setting<Integer> legitMineYLevel = new Setting<>(11);
/** /**
* When mining block of a certain type, try to mine two at once instead of one. * 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 * If the block above is also a goal block, set GoalBlock instead of GoalTwoBlocks
* If the block below is also a goal block, set GoalBlock to the position one down instead of GoalTwoBlocks * If the block below is also a goal block, set GoalBlock to the position one down instead of GoalTwoBlocks
*/ */
public final Setting<Boolean> forceInternalMining = new Setting<>(true); public Setting<Boolean> forceInternalMining = new Setting<>(true);
/** /**
* Modification to the previous setting, only has effect if forceInternalMining is true * Modification to the previous setting, only has effect if forceInternalMining is true
* If true, only apply the previous setting if the block adjacent to the goal isn't air. * If true, only apply the previous setting if the block adjacent to the goal isn't air.
*/ */
public final Setting<Boolean> internalMiningAirException = new Setting<>(true); public Setting<Boolean> internalMiningAirException = new Setting<>(true);
/** /**
* The actual GoalNear is set this distance away from the entity you're following * The actual GoalNear is set this distance away from the entity you're following
* <p> * <p>
* For example, set followOffsetDistance to 5 and followRadius to 0 to always stay precisely 5 blocks north of your follow target. * For example, set followOffsetDistance to 5 and followRadius to 0 to always stay precisely 5 blocks north of your follow target.
*/ */
public final Setting<Double> followOffsetDistance = new Setting<>(0D); public Setting<Double> followOffsetDistance = new Setting<>(0D);
/** /**
* The actual GoalNear is set in this direction from the entity you're following. This value is in degrees. * The actual GoalNear is set in this direction from the entity you're following
*/ */
public final Setting<Float> followOffsetDirection = new Setting<>(0F); public Setting<Float> followOffsetDirection = new Setting<>(0F);
/** /**
* The radius (for the GoalNear) of how close to your target position you actually have to be * The radius (for the GoalNear) of how close to your target position you actually have to be
*/ */
public final Setting<Integer> followRadius = new Setting<>(3); public Setting<Integer> 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 * Cached chunks (regardless of if they're in RAM or saved to disk) expire and are deleted after this number of seconds
@@ -572,55 +494,54 @@ public final class Settings {
* has to build up that cache from scratch. But after it's gone through an area just once, the next time will have zero * 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. * backtracking, since the entire area is now known and cached.
*/ */
public final Setting<Long> cachedChunksExpirySeconds = new Setting<>(-1L); public Setting<Long> cachedChunksExpirySeconds = new Setting<>(-1L);
/** /**
* The function that is called when Baritone will log to chat. This function can be added to * 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 * via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value}; * {@link Setting#value};
*/ */
public final Setting<Consumer<ITextComponent>> logger = new Setting<>(Minecraft.getMinecraft().ingameGUI.getChatGUI()::printChatMessage); public Setting<Consumer<ITextComponent>> logger = new Setting<>(Minecraft.getMinecraft().ingameGUI.getChatGUI()::printChatMessage);
/** /**
* The color of the current path * The color of the current path
*/ */
public final Setting<Color> colorCurrentPath = new Setting<>(Color.RED); public Setting<Color> colorCurrentPath = new Setting<>(Color.RED);
/** /**
* The color of the next path * The color of the next path
*/ */
public final Setting<Color> colorNextPath = new Setting<>(Color.MAGENTA); public Setting<Color> colorNextPath = new Setting<>(Color.MAGENTA);
/** /**
* The color of the blocks to break * The color of the blocks to break
*/ */
public final Setting<Color> colorBlocksToBreak = new Setting<>(Color.RED); public Setting<Color> colorBlocksToBreak = new Setting<>(Color.RED);
/** /**
* The color of the blocks to place * The color of the blocks to place
*/ */
public final Setting<Color> colorBlocksToPlace = new Setting<>(Color.GREEN); public Setting<Color> colorBlocksToPlace = new Setting<>(Color.GREEN);
/** /**
* The color of the blocks to walk into * The color of the blocks to walk into
*/ */
public final Setting<Color> colorBlocksToWalkInto = new Setting<>(Color.MAGENTA); public Setting<Color> colorBlocksToWalkInto = new Setting<>(Color.MAGENTA);
/** /**
* The color of the best path so far * The color of the best path so far
*/ */
public final Setting<Color> colorBestPathSoFar = new Setting<>(Color.BLUE); public Setting<Color> colorBestPathSoFar = new Setting<>(Color.BLUE);
/** /**
* The color of the path to the most recent considered node * The color of the path to the most recent considered node
*/ */
public final Setting<Color> colorMostRecentConsidered = new Setting<>(Color.CYAN); public Setting<Color> colorMostRecentConsidered = new Setting<>(Color.CYAN);
/** /**
* The color of the goal box * The color of the goal box
*/ */
public final Setting<Color> colorGoalBox = new Setting<>(Color.GREEN); public Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
/** /**
* A map of lowercase setting field names to their respective setting * A map of lowercase setting field names to their respective setting
@@ -632,12 +553,6 @@ public final class Settings {
*/ */
public final List<Setting<?>> allSettings; public final List<Setting<?>> allSettings;
public void reset() {
for (Setting setting : allSettings) {
setting.value = setting.defaultValue;
}
}
public class Setting<T> { public class Setting<T> {
public T value; public T value;
public final T defaultValue; public final T defaultValue;
@@ -15,8 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.api.cache; package baritone.api.behavior;
import baritone.api.behavior.memory.IRememberedInventory;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.Map; import java.util.Map;
@@ -25,7 +26,7 @@ import java.util.Map;
* @author Brady * @author Brady
* @since 9/23/2018 * @since 9/23/2018
*/ */
public interface IContainerMemory { public interface IMemoryBehavior extends IBehavior {
/** /**
* Gets a remembered inventory by its block position. * Gets a remembered inventory by its block position.
@@ -37,13 +37,7 @@ public interface IPathingBehavior extends IBehavior {
* *
* @return The estimated remaining ticks in the current segment. * @return The estimated remaining ticks in the current segment.
*/ */
default Optional<Double> ticksRemainingInSegment() { Optional<Double> ticksRemainingInSegment();
IPathExecutor current = getCurrent();
if (current == null) {
return Optional.empty();
}
return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition()));
}
/** /**
* @return The current pathing goal * @return The current pathing goal
@@ -53,9 +47,7 @@ public interface IPathingBehavior extends IBehavior {
/** /**
* @return Whether or not a path is currently being executed. * @return Whether or not a path is currently being executed.
*/ */
default boolean isPathing() { boolean isPathing();
return getCurrent() != null;
}
/** /**
* Cancels the pathing behavior or the current path calculation, and all processes that could be controlling path. * Cancels the pathing behavior or the current path calculation, and all processes that could be controlling path.
@@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.api.cache; package baritone.api.behavior.memory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
+2 -2
View File
@@ -37,12 +37,12 @@ public interface ICachedRegion extends IBlockTypeAccess {
boolean isCached(int blockX, int blockZ); boolean isCached(int blockX, int blockZ);
/** /**
* @return The X coordinate of this region * The X coordinate of this region
*/ */
int getX(); int getX();
/** /**
* @return The Z coordinate of this region * The Z coordinate of this region
*/ */
int getZ(); int getZ();
} }
+2 -8
View File
@@ -27,19 +27,13 @@ public interface IWorldData {
* Returns the cached world for this world. A cached world is a simplified format * Returns the cached world for this world. A cached world is a simplified format
* of a regular world, intended for use on multiplayer servers where chunks are not * of a regular world, intended for use on multiplayer servers where chunks are not
* traditionally stored to disk, allowing for long distance pathing with minimal disk usage. * traditionally stored to disk, allowing for long distance pathing with minimal disk usage.
*
* @return The cached world for this world
*/ */
ICachedWorld getCachedWorld(); ICachedWorld getCachedWorld();
/** /**
* Returns the waypoint collection for this world.
*
* @return The waypoint collection for this world * @return The waypoint collection for this world
*/ */
IWaypointCollection getWaypoints(); IWaypointCollection getWaypoints();
/**
* @return The {@link IContainerMemory} instance
* @see IContainerMemory
*/
IContainerMemory getContainerMemory();
} }
-15
View File
@@ -20,7 +20,6 @@ package baritone.api.cache;
import baritone.api.utils.IPlayerContext; import baritone.api.utils.IPlayerContext;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import java.util.List; import java.util.List;
@@ -43,18 +42,4 @@ public interface IWorldScanner {
* @return The matching block positions * @return The matching block positions
*/ */
List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius); List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius);
/**
* Scans a single chunk for the specified blocks.
*
* @param ctx The {@link IPlayerContext} containing player and world info that the
* scan is based upon
* @param blocks The blocks to scan for
* @param pos The position of the target chunk
* @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.
* @return The matching block positions
*/
List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold);
} }
@@ -20,7 +20,7 @@ package baritone.api.event.events;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
/** /**
* Called when the local player interacts with a block, can be either {@link Type#START_BREAK} or {@link Type#USE}. * Called when the local player interacts with a block, can be either {@link Type#BREAK} or {@link Type#USE}.
* *
* @author Brady * @author Brady
* @since 8/22/2018 * @since 8/22/2018
@@ -59,9 +59,9 @@ public final class BlockInteractEvent {
public enum Type { public enum Type {
/** /**
* We're starting to break the target block. * We're breaking the target block.
*/ */
START_BREAK, BREAK,
/** /**
* We're right clicking on the target block. Either placing or interacting with. * We're right clicking on the target block. Either placing or interacting with.
@@ -17,20 +17,22 @@
package baritone.api.event.events; 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 * @author Brady
* @since 8/1/2018 * @since 8/1/2018
*/ */
public final class ChatEvent extends Cancellable { public final class ChatEvent extends ManagedPlayerEvent.Cancellable {
/** /**
* The message being sent * The message being sent
*/ */
private final String message; private final String message;
public ChatEvent(String message) { public ChatEvent(EntityPlayerSP player, String message) {
super(player);
this.message = message; this.message = message;
} }
@@ -31,9 +31,7 @@ public final class ChunkEvent {
private final EventState state; private final EventState state;
/** /**
* The type of chunk event that occurred * The type of chunk event that occurred;
*
* @see Type
*/ */
private final Type type; private final Type type;
@@ -18,19 +18,22 @@
package baritone.api.event.events; package baritone.api.event.events;
import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.EventState;
import baritone.api.event.events.type.ManagedPlayerEvent;
import net.minecraft.client.entity.EntityPlayerSP;
/** /**
* @author Brady * @author Brady
* @since 8/21/2018 * @since 8/21/2018
*/ */
public final class PlayerUpdateEvent { public final class PlayerUpdateEvent extends ManagedPlayerEvent {
/** /**
* The state of the event * The state of the event
*/ */
private final EventState state; private final EventState state;
public PlayerUpdateEvent(EventState state) { public PlayerUpdateEvent(EntityPlayerSP player, EventState state) {
super(player);
this.state = state; this.state = state;
} }
@@ -17,6 +17,8 @@
package baritone.api.event.events; package baritone.api.event.events;
import baritone.api.event.events.type.ManagedPlayerEvent;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
@@ -24,7 +26,7 @@ import net.minecraft.entity.EntityLivingBase;
* @author Brady * @author Brady
* @since 8/21/2018 * @since 8/21/2018
*/ */
public final class RotationMoveEvent { public final class RotationMoveEvent extends ManagedPlayerEvent {
/** /**
* The type of event * The type of event
@@ -36,7 +38,8 @@ public final class RotationMoveEvent {
*/ */
private float yaw; private float yaw;
public RotationMoveEvent(Type type, float yaw) { public RotationMoveEvent(EntityPlayerSP player, Type type, float yaw) {
super(player);
this.type = type; this.type = type;
this.yaw = yaw; this.yaw = yaw;
} }
@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}
}
@@ -36,6 +36,9 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override @Override
default void onPlayerUpdate(PlayerUpdateEvent event) {} default void onPlayerUpdate(PlayerUpdateEvent event) {}
@Override
default void onProcessKeyBinds() {}
@Override @Override
default void onSendChatMessage(ChatEvent event) {} default void onSendChatMessage(ChatEvent event) {}
@@ -57,9 +60,6 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override @Override
default void onPlayerRotationMove(RotationMoveEvent event) {} default void onPlayerRotationMove(RotationMoveEvent event) {}
@Override
default void onPlayerSprintState(SprintStateEvent event) {}
@Override @Override
default void onBlockInteract(BlockInteractEvent event) {} default void onBlockInteract(BlockInteractEvent event) {}
@@ -23,9 +23,13 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiGameOver; import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.settings.GameSettings; import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
import net.minecraft.util.text.ITextComponent;
/** /**
* @author Brady * @author Brady
@@ -36,7 +40,6 @@ public interface IGameEventListener {
/** /**
* Run once per game tick before screen input is handled. * Run once per game tick before screen input is handled.
* *
* @param event The event
* @see Minecraft#runTick() * @see Minecraft#runTick()
*/ */
void onTick(TickEvent event); void onTick(TickEvent event);
@@ -44,15 +47,20 @@ public interface IGameEventListener {
/** /**
* Run once per game tick from before and after the player rotation is sent to the server. * Run once per game tick from before and after the player rotation is sent to the server.
* *
* @param event The event
* @see EntityPlayerSP#onUpdate() * @see EntityPlayerSP#onUpdate()
*/ */
void onPlayerUpdate(PlayerUpdateEvent event); void onPlayerUpdate(PlayerUpdateEvent event);
/**
* Run once per game tick from before keybinds are processed.
*
* @see Minecraft#processKeyBinds()
*/
void onProcessKeyBinds();
/** /**
* Runs whenever the client player sends a message to the server. * Runs whenever the client player sends a message to the server.
* *
* @param event The event
* @see EntityPlayerSP#sendChatMessage(String) * @see EntityPlayerSP#sendChatMessage(String)
*/ */
void onSendChatMessage(ChatEvent event); void onSendChatMessage(ChatEvent event);
@@ -60,7 +68,6 @@ public interface IGameEventListener {
/** /**
* Runs before and after whenever a chunk is either loaded, unloaded, or populated. * Runs before and after whenever a chunk is either loaded, unloaded, or populated.
* *
* @param event The event
* @see WorldClient#doPreChunk(int, int, boolean) * @see WorldClient#doPreChunk(int, int, boolean)
*/ */
void onChunkEvent(ChunkEvent event); void onChunkEvent(ChunkEvent event);
@@ -70,14 +77,13 @@ public interface IGameEventListener {
* <p> * <p>
* <b>Note:</b> {@link GameSettings#anaglyph} has been removed in Minecraft 1.13 * <b>Note:</b> {@link GameSettings#anaglyph} has been removed in Minecraft 1.13
* *
* @param event The event * @see EntityRenderer#renderWorldPass(int, float, long)
*/ */
void onRenderPass(RenderEvent event); void onRenderPass(RenderEvent event);
/** /**
* Runs before and after whenever a new world is loaded * Runs before and after whenever a new world is loaded
* *
* @param event The event
* @see Minecraft#loadWorld(WorldClient, String) * @see Minecraft#loadWorld(WorldClient, String)
*/ */
void onWorldEvent(WorldEvent event); void onWorldEvent(WorldEvent event);
@@ -85,7 +91,7 @@ public interface IGameEventListener {
/** /**
* Runs before a outbound packet is sent * Runs before a outbound packet is sent
* *
* @param event The event * @see NetworkManager#dispatchPacket(Packet, GenericFutureListener[])
* @see Packet * @see Packet
* @see GenericFutureListener * @see GenericFutureListener
*/ */
@@ -94,7 +100,7 @@ public interface IGameEventListener {
/** /**
* Runs before an inbound packet is processed * Runs before an inbound packet is processed
* *
* @param event The event * @see NetworkManager#dispatchPacket(Packet, GenericFutureListener[])
* @see Packet * @see Packet
* @see GenericFutureListener * @see GenericFutureListener
*/ */
@@ -104,37 +110,31 @@ public interface IGameEventListener {
* Run once per game tick from before and after the player's moveRelative method is called * Run once per game tick from before and after the player's moveRelative method is called
* and before and after the player jumps. * and before and after the player jumps.
* *
* @param event The event
* @see Entity#moveRelative(float, float, float, float) * @see Entity#moveRelative(float, float, float, float)
* @see EntityLivingBase#jump()
*/ */
void onPlayerRotationMove(RotationMoveEvent event); void onPlayerRotationMove(RotationMoveEvent event);
/**
* Called whenever the sprint keybind state is checked in {@link EntityPlayerSP#onLivingUpdate}
*
* @param event The event
* @see EntityPlayerSP#onLivingUpdate()
*/
void onPlayerSprintState(SprintStateEvent event);
/** /**
* Called when the local player interacts with a block, whether it is breaking or opening/placing. * Called when the local player interacts with a block, whether it is breaking or opening/placing.
* *
* @param event The event * @see Minecraft#clickMouse()
* @see Minecraft#rightClickMouse()
*/ */
void onBlockInteract(BlockInteractEvent event); void onBlockInteract(BlockInteractEvent event);
/** /**
* Called when the local player dies, as indicated by the creation of the {@link GuiGameOver} screen. * Called when the local player dies, as indicated by the creation of the {@link GuiGameOver} screen.
* *
* @see GuiGameOver * @see GuiGameOver(ITextComponent)
* @see ITextComponent
*/ */
void onPlayerDeath(); void onPlayerDeath();
/** /**
* When the pathfinder's state changes * When the pathfinder's state changes
* *
* @param event The event * @param event
*/ */
void onPathEvent(PathEvent event); void onPathEvent(PathEvent event);
} }
@@ -21,6 +21,7 @@ import baritone.api.Settings;
import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.IMovement; import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
import net.minecraft.world.World;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -51,8 +52,6 @@ public interface IPath {
/** /**
* This path is actually going to be executed in the world. Do whatever additional processing is required. * 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) * (as opposed to Path objects that are just constructed every frame for rendering)
*
* @return The result of path post processing
*/ */
default IPath postProcess() { default IPath postProcess() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@@ -105,28 +104,33 @@ public interface IPath {
* Returns the estimated number of ticks to complete the path from the given node index. * 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 * @param pathPosition The index of the node we're calculating from
* @return The estimated number of ticks remaining frm the given position * @return The estimated number of ticks remaining from the given position
*/ */
default double ticksRemainingFrom(int pathPosition) { default double ticksRemainingFrom(int pathPosition) {
double sum = 0; double sum = 0;
//this is fast because we aren't requesting recalculation, it's just cached //this is fast because we aren't requesting recalculation, it's just cached
List<IMovement> movements = movements(); for (int i = pathPosition; i < movements().size(); i++) {
for (int i = pathPosition; i < movements.size(); i++) { sum += movements().get(i).getCost();
sum += movements.get(i).getCost();
} }
return sum; return sum;
} }
/**
* Returns the estimated amount of time needed to complete this path from start to finish
*
* @return The estimated amount of time, in ticks
*/
default double totalTicks() {
return ticksRemainingFrom(0);
}
/** /**
* Cuts off this path at the loaded chunk border, and returns the resulting path. Default * Cuts off this path at the loaded chunk border, and returns the resulting path. Default
* implementation just returns this path, without the intended functionality. * implementation just returns this path, without the intended functionality.
* <p>
* The argument is supposed to be a BlockStateInterface LOL LOL LOL LOL LOL
* *
* @param bsi The block state lookup, highly cursed
* @return The result of this cut-off operation * @return The result of this cut-off operation
*/ */
default IPath cutoffAtLoadedChunks(Object bsi) { default IPath cutoffAtLoadedChunks(World world) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -134,7 +138,6 @@ public interface IPath {
* Cuts off this path using the min length and cutoff factor settings, and returns the resulting path. * 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. * Default implementation just returns this path, without the intended functionality.
* *
* @param destination The end goal of this path
* @return The result of this cut-off operation * @return The result of this cut-off operation
* @see Settings#pathCutoffMinimumLength * @see Settings#pathCutoffMinimumLength
* @see Settings#pathCutoffFactor * @see Settings#pathCutoffFactor
@@ -34,8 +34,6 @@ public interface IPathFinder {
/** /**
* Calculate the path in full. Will take several seconds. * Calculate the path in full. Will take several seconds.
* *
* @param primaryTimeout If a path is found, the path finder will stop after this amount of time
* @param failureTimeout If a path isn't found, the path finder will continue for this amount of time
* @return The final path * @return The final path
*/ */
PathCalculationResult calculate(long primaryTimeout, long failureTimeout); PathCalculationResult calculate(long primaryTimeout, long failureTimeout);
@@ -22,26 +22,10 @@ import baritone.api.process.PathingCommand;
import java.util.Optional; import java.util.Optional;
/**
* @author leijurv
*/
public interface IPathingControlManager { public interface IPathingControlManager {
/**
* Registers a process with this pathing control manager. See {@link IBaritoneProcess} for more details.
*
* @param process The process
* @see IBaritoneProcess
*/
void registerProcess(IBaritoneProcess process); void registerProcess(IBaritoneProcess process);
/**
* @return The most recent {@link IBaritoneProcess} that had control
*/
Optional<IBaritoneProcess> mostRecentInControl(); Optional<IBaritoneProcess> mostRecentInControl();
/**
* @return The most recent pathing command executed
*/
Optional<PathingCommand> mostRecentCommand(); Optional<PathingCommand> mostRecentCommand();
} }
@@ -30,9 +30,6 @@ public interface Goal {
* Returns whether or not the specified position * Returns whether or not the specified position
* meets the requirement for this goal based. * meets the requirement for this goal based.
* *
* @param x The goal X position
* @param y The goal Y position
* @param z The goal Z position
* @return Whether or not it satisfies this goal * @return Whether or not it satisfies this goal
*/ */
boolean isInGoal(int x, int y, int z); boolean isInGoal(int x, int y, int z);
@@ -40,9 +37,6 @@ public interface Goal {
/** /**
* Estimate the number of ticks it will take to get to the goal * Estimate the number of ticks it will take to get to the goal
* *
* @param x The goal X position
* @param y The goal Y position
* @param z The goal Z position
* @return The estimate number of ticks to satisfy the goal * @return The estimate number of ticks to satisfy the goal
*/ */
double heuristic(int x, int y, int z); double heuristic(int x, int y, int z);
@@ -20,6 +20,8 @@ package baritone.api.pathing.movement;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.List;
/** /**
* @author Brady * @author Brady
* @since 10/8/2018 * @since 10/8/2018
@@ -56,4 +58,10 @@ public interface IMovement {
BetterBlockPos getDest(); BetterBlockPos getDest();
BlockPos getDirection(); BlockPos getDirection();
List<BlockPos> toBreak();
List<BlockPos> toPlace();
List<BlockPos> toWalkInto();
} }
@@ -26,6 +26,4 @@ import baritone.api.pathing.calc.IPath;
public interface IPathExecutor { public interface IPathExecutor {
IPath getPath(); IPath getPath();
int getPosition();
} }
@@ -17,6 +17,7 @@
package baritone.api.process; package baritone.api.process;
import baritone.api.IBaritone;
import baritone.api.behavior.IPathingBehavior; import baritone.api.behavior.IPathingBehavior;
import baritone.api.event.events.PathEvent; import baritone.api.event.events.PathEvent;
@@ -24,10 +25,8 @@ import baritone.api.event.events.PathEvent;
* A process that can control the PathingBehavior. * A process that can control the PathingBehavior.
* <p> * <p>
* Differences between a baritone process and a behavior: * Differences between a baritone process and a behavior:
* <ul> * Only one baritone process can be active at a time
* <li>Only one baritone process can be active at a time</li> * PathingBehavior can only be controlled by a process
* <li>PathingBehavior can only be controlled by a process</li>
* </ul>
* <p> * <p>
* That's it actually * That's it actually
* *
@@ -84,6 +83,13 @@ public interface IBaritoneProcess {
*/ */
double 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. * Returns a user-friendly name for this process. Suitable for a HUD.
* *
@@ -27,7 +27,9 @@ import net.minecraft.client.settings.KeyBinding;
*/ */
public interface IInputOverrideHandler extends IBehavior { public interface IInputOverrideHandler extends IBehavior {
Boolean isInputForcedDown(KeyBinding key); default boolean isInputForcedDown(KeyBinding key) {
return isInputForcedDown(Input.getInputForBind(key));
}
boolean isInputForcedDown(Input input); boolean isInputForcedDown(Input input);
@@ -20,6 +20,7 @@ package baritone.api.utils;
import baritone.api.cache.IWorldData; import baritone.api.cache.IWorldData;
import net.minecraft.block.BlockSlab; import net.minecraft.block.BlockSlab;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.PlayerControllerMP;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
@@ -36,7 +37,7 @@ public interface IPlayerContext {
EntityPlayerSP player(); EntityPlayerSP player();
IPlayerController playerController(); PlayerControllerMP playerController();
World world(); World world();
@@ -1,46 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ClickType;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameType;
/**
* @author Brady
* @since 12/14/2018
*/
public interface IPlayerController {
boolean onPlayerDamageBlock(BlockPos pos, EnumFacing side);
void resetBlockRemoving();
ItemStack windowClick(int windowId, int slotId, int mouseButton, ClickType type, EntityPlayer player);
void setGameType(GameType type);
GameType getGameType();
default double getBlockReachDistance() {
return this.getGameType().isCreative() ? 5.0F : 4.5F;
}
}
@@ -15,21 +15,13 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.api.event.events; package baritone.api.utils;
/** /**
* @author Brady * @author Brady
* @since 1/18/2019 * @since 9/23/2018
*/ */
public final class SprintStateEvent { public class Logger {
private Boolean state;
public final void setState(boolean state) {
this.state = state;
}
public final Boolean getState() {
return this.state;
}
} }
@@ -19,7 +19,6 @@ package baritone.api.utils;
import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPath;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
public class PathCalculationResult { public class PathCalculationResult {
@@ -32,9 +31,11 @@ public class PathCalculationResult {
} }
public PathCalculationResult(Type type, IPath path) { public PathCalculationResult(Type type, IPath path) {
Objects.requireNonNull(type);
this.path = path; this.path = path;
this.type = type; this.type = type;
if (type == null) {
throw new IllegalArgumentException("come on");
}
} }
public final Optional<IPath> getPath() { public final Optional<IPath> getPath() {
@@ -34,9 +34,7 @@ public final class RayTraceUtils {
* any entity collisions can be ignored, because this method will not recognize if an * 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. * entity is in the way or not. The local player's block reach distance will be used.
* *
* @param entity The entity representing the raytrace source * @param rotation The rotation to raytrace towards
* @param rotation The rotation to raytrace towards
* @param blockReachDistance The block reach distance of the entity
* @return The calculated raytrace result * @return The calculated raytrace result
*/ */
public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance) { public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance) {
+1 -12
View File
@@ -110,17 +110,6 @@ public class Rotation {
); );
} }
/**
* Is really close to
*
* @param other another rotation
* @return are they really close
*/
public boolean isReallyCloseTo(Rotation other) {
float yawDiff = Math.abs(this.yaw - other.yaw); // you cant fool me
return (yawDiff < 0.01 || yawDiff > 359.9) && Math.abs(this.pitch - other.pitch) < 0.01;
}
/** /**
* Clamps the specified pitch value between -90 and 90. * Clamps the specified pitch value between -90 and 90.
* *
@@ -142,7 +131,7 @@ public class Rotation {
if (newYaw < -180F) { if (newYaw < -180F) {
newYaw += 360F; newYaw += 360F;
} }
if (newYaw > 180F) { if (newYaw >= 180F) {
newYaw -= 360F; newYaw -= 360F;
} }
return newYaw; return newYaw;
@@ -127,16 +127,6 @@ public final class RotationUtils {
return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2)); return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
} }
/**
* @param ctx Context for the viewing entity
* @param pos The target block position
* @return The optional rotation
* @see #reachable(EntityPlayerSP, BlockPos, double)
*/
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos) {
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
}
/** /**
* Determines if the specified entity is able to reach the center of any of the sides * 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, * of the specified block. It first checks if the block center is reachable, and if so,
@@ -144,9 +134,8 @@ public final class RotationUtils {
* side that is reachable. The return type will be {@link Optional#empty()} if the entity is * 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. * unable to reach any of the sides of the block.
* *
* @param entity The viewing entity * @param entity The viewing entity
* @param pos The target block position * @param pos The target block position
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation * @return The optional rotation
*/ */
public static Optional<Rotation> reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance) { public static Optional<Rotation> reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance) {
@@ -189,10 +178,9 @@ public final class RotationUtils {
* the given offsetted position. The return type will be {@link Optional#empty()} if * 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. * the entity is unable to reach the block with the offset applied.
* *
* @param entity The viewing entity * @param entity The viewing entity
* @param pos The target block position * @param pos The target block position
* @param offsetPos The position of the block with the offset applied. * @param offsetPos The position of the block with the offset applied.
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation * @return The optional rotation
*/ */
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) { public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) {
@@ -214,9 +202,8 @@ public final class RotationUtils {
* Determines if the specified entity is able to reach the specified block where it is * Determines if the specified entity is able to reach the specified block where it is
* looking at the direct center of it's hitbox. * looking at the direct center of it's hitbox.
* *
* @param entity The viewing entity * @param entity The viewing entity
* @param pos The target block position * @param pos The target block position
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation * @return The optional rotation
*/ */
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) { public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) {
@@ -18,77 +18,56 @@
package baritone.api.utils; package baritone.api.utils;
import baritone.api.Settings; import baritone.api.Settings;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import java.awt.*; import java.awt.*;
import java.io.BufferedReader; import java.io.File;
import java.io.BufferedWriter; import java.io.FileOutputStream;
import java.io.IOException; import java.util.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static net.minecraft.client.Minecraft.getMinecraft;
public class SettingsUtil { public class SettingsUtil {
private static final Path SETTINGS_PATH = getMinecraft().gameDir.toPath().resolve("baritone").resolve("settings.txt"); private static final File settingsFile = new File(new File(Minecraft.getMinecraft().gameDir, "baritone"), "settings.txt");
private static final Pattern SETTING_PATTERN = Pattern.compile("^(?<setting>[^ ]+) +(?<value>[^ ]+)"); // 2 words separated by spaces
private static final Map<Class<?>, SettingsIO> map; private static final Map<Class<?>, SettingsIO> map;
private static boolean isComment(String line) { public static void readAndApply(Settings settings) {
return line.startsWith("#") || line.startsWith("//"); try (Scanner scan = new Scanner(settingsFile)) {
} while (scan.hasNextLine()) {
String line = scan.nextLine();
private static void forEachLine(Path file, Consumer<String> consumer) throws IOException { if (line.isEmpty()) {
try (BufferedReader scan = Files.newBufferedReader(file)) {
String line;
while ((line = scan.readLine()) != null) {
if (line.isEmpty() || isComment(line)) {
continue; continue;
} }
consumer.accept(line); if (line.startsWith("#") || line.startsWith("//")) {
} continue;
}
}
public static void readAndApply(Settings settings) {
try {
forEachLine(SETTINGS_PATH, line -> {
Matcher matcher = SETTING_PATTERN.matcher(line);
if (!matcher.matches()) {
System.out.println("Invalid syntax in setting file: " + line);
return;
} }
int space = line.indexOf(" ");
String settingName = matcher.group("setting").toLowerCase(); if (space == -1) {
String settingValue = matcher.group("value"); 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 { try {
parseAndApply(settings, settingName, settingValue); parseAndApply(settings, settingName, settingValue);
} catch (Exception ex) { } catch (Exception ex) {
System.out.println("Unable to parse line " + line);
ex.printStackTrace(); ex.printStackTrace();
System.out.println("Unable to parse line " + line);
} }
}); }
} catch (Exception ex) { } catch (Exception ex) {
System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
ex.printStackTrace(); 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) { public static synchronized void save(Settings settings) {
try (BufferedWriter out = Files.newBufferedWriter(SETTINGS_PATH)) { try (FileOutputStream out = new FileOutputStream(settingsFile)) {
for (Settings.Setting setting : settings.allSettings) { for (Settings.Setting setting : settings.allSettings) {
if (setting.get() == null) { if (setting.get() == null) {
System.out.println("NULL SETTING?" + setting.getName()); System.out.println("NULL SETTING?" + setting.getName());
@@ -104,11 +83,11 @@ public class SettingsUtil {
if (io == null) { if (io == null) {
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName()); throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName());
} }
out.write(setting.getName() + " " + io.toString.apply(setting.get()) + "\n"); out.write((setting.getName() + " " + io.toString.apply(setting.get()) + "\n").getBytes());
} }
} catch (Exception ex) { } catch (Exception ex) {
System.out.println("Exception thrown while saving Baritone settings!");
ex.printStackTrace(); ex.printStackTrace();
System.out.println("Exception while saving Baritone settings!");
} }
} }
@@ -36,8 +36,7 @@ public final class VecUtils {
/** /**
* Calculates the center of the block at the specified position's bounding box * Calculates the center of the block at the specified position's bounding box
* *
* @param world The world that the block is in, used to provide the bounding box * @param pos The block position
* @param pos The block position
* @return The center of the block's bounding box * @return The center of the block's bounding box
* @see #getBlockPosCenter(BlockPos) * @see #getBlockPosCenter(BlockPos)
*/ */
@@ -82,9 +81,10 @@ public final class VecUtils {
* @see #getBlockPosCenter(BlockPos) * @see #getBlockPosCenter(BlockPos)
*/ */
public static double distanceToCenter(BlockPos pos, double x, double y, double z) { public static double distanceToCenter(BlockPos pos, double x, double y, double z) {
double xdiff = pos.getX() + 0.5 - x; Vec3d center = getBlockPosCenter(pos);
double ydiff = pos.getY() + 0.5 - y; double xdiff = x - center.x;
double zdiff = pos.getZ() + 0.5 - z; double ydiff = y - center.y;
double zdiff = z - center.z;
return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff); return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
} }
@@ -0,0 +1,98 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Do you not like having a blocking "receiveMessage" thingy?
* <p>
* Do you prefer just being able to get a list of all messages received since the last tick?
* <p>
* If so, this class is for you!
*
* @author leijurv
*/
public class BufferedConnection implements IConnection {
private final IConnection wrapped;
private final LinkedBlockingQueue<iMessage> queue;
private volatile transient IOException thrownOnRead;
public BufferedConnection(IConnection wrapped) {
this(wrapped, Integer.MAX_VALUE); // LinkedBlockingQueue accepts this as "no limit"
}
public BufferedConnection(IConnection wrapped, int maxInternalQueueSize) {
this.wrapped = wrapped;
this.queue = new LinkedBlockingQueue<>();
this.thrownOnRead = null;
new Thread(() -> {
try {
while (thrownOnRead == null) {
queue.put(wrapped.receiveMessage());
}
} catch (IOException e) {
thrownOnRead = e;
} catch (InterruptedException e) {
thrownOnRead = new IOException("Interrupted while enqueueing", e);
}
}).start();
}
@Override
public void sendMessage(iMessage message) throws IOException {
wrapped.sendMessage(message);
}
@Override
public iMessage receiveMessage() {
throw new UnsupportedOperationException("BufferedConnection can only be read from non-blockingly");
}
@Override
public void close() {
wrapped.close();
thrownOnRead = new EOFException("Closed");
}
public List<iMessage> receiveMessagesNonBlocking() throws IOException {
ArrayList<iMessage> msgs = new ArrayList<>();
queue.drainTo(msgs); // preserves order -- first message received will be first in this arraylist
if (msgs.isEmpty() && thrownOnRead != null) {
IOException up = new IOException("BufferedConnection wrapped", thrownOnRead);
throw up;
}
return msgs;
}
public void handleAllPendingMessages(IMessageListener listener) throws IOException {
receiveMessagesNonBlocking().forEach(msg -> msg.handle(listener));
}
public static BufferedConnection makeBuffered(IConnection conn) {
if (conn instanceof BufferedConnection) {
return (BufferedConnection) conn;
} else {
return new BufferedConnection(conn);
}
}
}
@@ -0,0 +1,54 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.DataInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public enum ConstructingDeserializer implements MessageDeserializer {
INSTANCE;
private final List<Class<? extends iMessage>> MSGS;
ConstructingDeserializer() {
MSGS = new ArrayList<>();
// imagine doing something in reflect but it's actually concise and you don't need to catch 42069 different exceptions. huh.
for (Method m : IMessageListener.class.getDeclaredMethods()) {
if (m.getName().equals("handle")) {
MSGS.add((Class<? extends iMessage>) m.getParameterTypes()[0]);
}
}
}
@Override
public synchronized iMessage deserialize(DataInputStream in) throws IOException {
int type = ((int) in.readByte()) & 0xff;
try {
return MSGS.get(type).getConstructor(DataInputStream.class).newInstance(in);
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException ex) {
throw new IOException("Unknown message type " + type, ex);
}
}
public byte getHeader(Class<? extends iMessage> klass) {
return (byte) MSGS.indexOf(klass);
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.IOException;
public interface IConnection {
void sendMessage(iMessage message) throws IOException;
iMessage receiveMessage() throws IOException;
void close();
}
@@ -0,0 +1,46 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import cabaletta.comms.downward.MessageChat;
import cabaletta.comms.downward.MessageComputationRequest;
import cabaletta.comms.upward.MessageComputationResponse;
import cabaletta.comms.upward.MessageStatus;
public interface IMessageListener {
default void handle(MessageStatus message) {
unhandled(message);
}
default void handle(MessageChat message) {
unhandled(message);
}
default void handle(MessageComputationRequest message) {
unhandled(message);
}
default void handle(MessageComputationResponse message) {
unhandled(message);
}
default void unhandled(iMessage msg) {
// can override this to throw UnsupportedOperationException, if you want to make sure you're handling everything
// default is to silently ignore messages without handlers
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.DataInputStream;
import java.io.IOException;
public interface MessageDeserializer {
iMessage deserialize(DataInputStream in) throws IOException;
}
+99
View File
@@ -0,0 +1,99 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.EOFException;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Do you want a socket to localhost without actually making a gross real socket to localhost?
*/
public class Pipe<T extends iMessage> {
private final LinkedBlockingQueue<Optional<iMessage>> AtoB;
private final LinkedBlockingQueue<Optional<iMessage>> BtoA;
private final PipedConnection A;
private final PipedConnection B;
private volatile boolean closed;
public Pipe() {
this.AtoB = new LinkedBlockingQueue<>();
this.BtoA = new LinkedBlockingQueue<>();
this.A = new PipedConnection(BtoA, AtoB);
this.B = new PipedConnection(AtoB, BtoA);
}
public PipedConnection getA() {
return A;
}
public PipedConnection getB() {
return B;
}
public class PipedConnection implements IConnection {
private final LinkedBlockingQueue<Optional<iMessage>> in;
private final LinkedBlockingQueue<Optional<iMessage>> out;
private PipedConnection(LinkedBlockingQueue<Optional<iMessage>> in, LinkedBlockingQueue<Optional<iMessage>> out) {
this.in = in;
this.out = out;
}
@Override
public void sendMessage(iMessage message) throws IOException {
if (closed) {
throw new EOFException("Closed");
}
try {
out.put(Optional.of(message));
} catch (InterruptedException e) {
// this can never happen since the LinkedBlockingQueues are not constructed with a maximum capacity, see above
}
}
@Override
public iMessage receiveMessage() throws IOException {
if (closed) {
throw new EOFException("Closed");
}
try {
Optional<iMessage> t = in.take();
if (!t.isPresent()) {
throw new EOFException("Closed");
}
return t.get();
} catch (InterruptedException e) {
// again, cannot happen
// but we have to throw something
throw new IllegalStateException(e);
}
}
@Override
public void close() {
closed = true;
try {
AtoB.put(Optional.empty()); // unstick threads
BtoA.put(Optional.empty());
} catch (InterruptedException e) {
}
}
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.*;
public class SerializedConnection implements IConnection {
private final DataInputStream in;
private final DataOutputStream out;
private final MessageDeserializer deserializer;
public SerializedConnection(InputStream in, OutputStream out) {
this(ConstructingDeserializer.INSTANCE, in, out);
}
public SerializedConnection(MessageDeserializer d, InputStream in, OutputStream out) {
this.in = new DataInputStream(in);
this.out = new DataOutputStream(out);
this.deserializer = d;
}
@Override
public synchronized void sendMessage(iMessage message) throws IOException {
message.writeHeader(out);
message.write(out);
}
@Override
public iMessage receiveMessage() throws IOException {
return deserializer.deserialize(in);
}
@Override
public void close() {
try {
in.close();
} catch (IOException e) {
}
try {
out.close();
} catch (IOException e) {
}
}
}
@@ -0,0 +1,27 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.IOException;
import java.net.Socket;
public class SocketConnection extends SerializedConnection {
public SocketConnection(Socket s) throws IOException {
super(s.getInputStream(), s.getOutputStream());
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms.downward;
import cabaletta.comms.IMessageListener;
import cabaletta.comms.iMessage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MessageChat implements iMessage {
public final String msg;
public MessageChat(DataInputStream in) throws IOException {
this.msg = in.readUTF();
}
public MessageChat(String msg) {
this.msg = msg;
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeUTF(msg);
}
@Override
public void handle(IMessageListener listener) {
listener.handle(this);
}
}
@@ -0,0 +1,62 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms.downward;
import cabaletta.comms.IMessageListener;
import cabaletta.comms.iMessage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MessageComputationRequest implements iMessage {
public final long computationID;
public final int startX;
public final int startY;
public final int startZ;
public final String goal; // TODO find a better way to do this lol
public MessageComputationRequest(DataInputStream in) throws IOException {
this.computationID = in.readLong();
this.startX = in.readInt();
this.startY = in.readInt();
this.startZ = in.readInt();
this.goal = in.readUTF();
}
public MessageComputationRequest(long computationID, int startX, int startY, int startZ, String goal) {
this.computationID = computationID;
this.startX = startX;
this.startY = startY;
this.startZ = startZ;
this.goal = goal;
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeLong(computationID);
out.writeInt(startX);
out.writeInt(startY);
out.writeUTF(goal);
}
@Override
public void handle(IMessageListener listener) {
listener.handle(this);
}
}
@@ -0,0 +1,44 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* hell yeah
* <p>
* <p>
* dumb android users cant read this file
* <p>
*
* @author leijurv
*/
public interface iMessage {
void write(DataOutputStream out) throws IOException;
default void writeHeader(DataOutputStream out) throws IOException {
out.writeByte(getHeader());
}
default byte getHeader() {
return ConstructingDeserializer.INSTANCE.getHeader(getClass());
}
void handle(IMessageListener listener);
}
@@ -0,0 +1,72 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms.upward;
import cabaletta.comms.IMessageListener;
import cabaletta.comms.iMessage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MessageComputationResponse implements iMessage {
public final long computationID;
public final int pathLength;
public final double pathCost;
public final boolean endsInGoal;
public final int endX;
public final int endY;
public final int endZ;
public MessageComputationResponse(DataInputStream in) throws IOException {
this.computationID = in.readLong();
this.pathLength = in.readInt();
this.pathCost = in.readDouble();
this.endsInGoal = in.readBoolean();
this.endX = in.readInt();
this.endY = in.readInt();
this.endZ = in.readInt();
}
public MessageComputationResponse(long computationID, int pathLength, double pathCost, boolean endsInGoal, int endX, int endY, int endZ) {
this.computationID = computationID;
this.pathLength = pathLength;
this.pathCost = pathCost;
this.endsInGoal = endsInGoal;
this.endX = endX;
this.endY = endY;
this.endZ = endZ;
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeLong(computationID);
out.writeInt(pathLength);
out.writeDouble(pathCost);
out.writeBoolean(endsInGoal);
out.writeInt(endX);
out.writeInt(endY);
out.writeInt(endZ);
}
@Override
public void handle(IMessageListener listener) {
listener.handle(this);
}
}
@@ -0,0 +1,124 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package cabaletta.comms.upward;
import cabaletta.comms.IMessageListener;
import cabaletta.comms.iMessage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MessageStatus implements iMessage {
public final double x;
public final double y;
public final double z;
public final float yaw;
public final float pitch;
public final boolean onGround;
public final float health;
public final float saturation;
public final int foodLevel;
public final int pathStartX;
public final int pathStartY;
public final int pathStartZ;
public final boolean hasCurrentSegment;
public final boolean hasNextSegment;
public final boolean calcInProgress;
public final double ticksRemainingInCurrent;
public final boolean calcFailedLastTick;
public final boolean safeToCancel;
public final String currentGoal;
public final String currentProcess;
public MessageStatus(DataInputStream in) throws IOException {
this.x = in.readDouble();
this.y = in.readDouble();
this.z = in.readDouble();
this.yaw = in.readFloat();
this.pitch = in.readFloat();
this.onGround = in.readBoolean();
this.health = in.readFloat();
this.saturation = in.readFloat();
this.foodLevel = in.readInt();
this.pathStartX = in.readInt();
this.pathStartY = in.readInt();
this.pathStartZ = in.readInt();
this.hasCurrentSegment = in.readBoolean();
this.hasNextSegment = in.readBoolean();
this.calcInProgress = in.readBoolean();
this.ticksRemainingInCurrent = in.readDouble();
this.calcFailedLastTick = in.readBoolean();
this.safeToCancel = in.readBoolean();
this.currentGoal = in.readUTF();
this.currentProcess = in.readUTF();
}
public MessageStatus(double x, double y, double z, float yaw, float pitch, boolean onGround, float health, float saturation, int foodLevel, int pathStartX, int pathStartY, int pathStartZ, boolean hasCurrentSegment, boolean hasNextSegment, boolean calcInProgress, double ticksRemainingInCurrent, boolean calcFailedLastTick, boolean safeToCancel, String currentGoal, String currentProcess) {
this.x = x;
this.y = y;
this.z = z;
this.yaw = yaw;
this.pitch = pitch;
this.onGround = onGround;
this.health = health;
this.saturation = saturation;
this.foodLevel = foodLevel;
this.pathStartX = pathStartX;
this.pathStartY = pathStartY;
this.pathStartZ = pathStartZ;
this.hasCurrentSegment = hasCurrentSegment;
this.hasNextSegment = hasNextSegment;
this.calcInProgress = calcInProgress;
this.ticksRemainingInCurrent = ticksRemainingInCurrent;
this.calcFailedLastTick = calcFailedLastTick;
this.safeToCancel = safeToCancel;
this.currentGoal = currentGoal;
this.currentProcess = currentProcess;
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeDouble(x);
out.writeDouble(y);
out.writeDouble(z);
out.writeFloat(yaw);
out.writeFloat(pitch);
out.writeBoolean(onGround);
out.writeFloat(health);
out.writeFloat(saturation);
out.writeInt(foodLevel);
out.writeInt(pathStartX);
out.writeInt(pathStartY);
out.writeInt(pathStartZ);
out.writeBoolean(hasCurrentSegment);
out.writeBoolean(hasNextSegment);
out.writeBoolean(calcInProgress);
out.writeDouble(ticksRemainingInCurrent);
out.writeBoolean(calcFailedLastTick);
out.writeBoolean(safeToCancel);
out.writeUTF(currentGoal);
out.writeUTF(currentProcess);
}
@Override
public void handle(IMessageListener listener) {
listener.handle(this);
}
}
@@ -52,7 +52,7 @@ public class MixinEntity {
private void preMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) { private void preMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) {
// noinspection ConstantConditions // noinspection ConstantConditions
if (EntityPlayerSP.class.isInstance(this)) { if (EntityPlayerSP.class.isInstance(this)) {
this.motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw); this.motionUpdateRotationEvent = new RotationMoveEvent((EntityPlayerSP) (Object) this, RotationMoveEvent.Type.MOTION_UPDATE, this.rotationYaw);
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerRotationMove(this.motionUpdateRotationEvent); BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerRotationMove(this.motionUpdateRotationEvent);
} }
} }
@@ -55,7 +55,7 @@ public abstract class MixinEntityLivingBase extends Entity {
private void preMoveRelative(CallbackInfo ci) { private void preMoveRelative(CallbackInfo ci) {
// noinspection ConstantConditions // noinspection ConstantConditions
if (EntityPlayerSP.class.isInstance(this)) { if (EntityPlayerSP.class.isInstance(this)) {
this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.rotationYaw); this.jumpRotationEvent = new RotationMoveEvent((EntityPlayerSP) (Object) this, RotationMoveEvent.Type.JUMP, this.rotationYaw);
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent); BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent);
} }
} }
@@ -21,11 +21,8 @@ import baritone.api.BaritoneAPI;
import baritone.api.behavior.IPathingBehavior; import baritone.api.behavior.IPathingBehavior;
import baritone.api.event.events.ChatEvent; import baritone.api.event.events.ChatEvent;
import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.SprintStateEvent;
import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.EventState;
import baritone.behavior.LookBehavior;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.player.PlayerCapabilities; import net.minecraft.entity.player.PlayerCapabilities;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -46,7 +43,7 @@ public class MixinEntityPlayerSP {
cancellable = true cancellable = true
) )
private void sendChatMessage(String msg, CallbackInfo ci) { private void sendChatMessage(String msg, CallbackInfo ci) {
ChatEvent event = new ChatEvent(msg); ChatEvent event = new ChatEvent((EntityPlayerSP) (Object) this, msg);
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onSendChatMessage(event); BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onSendChatMessage(event);
if (event.isCancelled()) { if (event.isCancelled()) {
ci.cancel(); ci.cancel();
@@ -63,7 +60,7 @@ public class MixinEntityPlayerSP {
) )
) )
private void onPreUpdate(CallbackInfo ci) { private void onPreUpdate(CallbackInfo ci) {
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.PRE)); BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent((EntityPlayerSP) (Object) this, EventState.PRE));
} }
@Inject( @Inject(
@@ -76,7 +73,7 @@ public class MixinEntityPlayerSP {
) )
) )
private void onPostUpdate(CallbackInfo ci) { private void onPostUpdate(CallbackInfo ci) {
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST)); BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent((EntityPlayerSP) (Object) this, EventState.POST));
} }
@Redirect( @Redirect(
@@ -90,27 +87,4 @@ public class MixinEntityPlayerSP {
IPathingBehavior pathingBehavior = BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getPathingBehavior(); IPathingBehavior pathingBehavior = BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getPathingBehavior();
return !pathingBehavior.isPathing() && capabilities.allowFlying; return !pathingBehavior.isPathing() && capabilities.allowFlying;
} }
@Redirect(
method = "onLivingUpdate",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/settings/KeyBinding.isKeyDown()Z"
)
)
private boolean isKeyDown(KeyBinding keyBinding) {
SprintStateEvent event = new SprintStateEvent();
BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getGameEventHandler().onPlayerSprintState(event);
return event.getState() == null ? keyBinding.isKeyDown() : event.getState();
}
@Inject(
method = "updateRidden",
at = @At(
value = "HEAD"
)
)
private void updateRidden(CallbackInfo cb) {
((LookBehavior) BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this).getLookBehavior()).pig();
}
} }
@@ -18,10 +18,8 @@
package baritone.launch.mixins; package baritone.launch.mixins;
import baritone.api.BaritoneAPI; import baritone.api.BaritoneAPI;
import baritone.utils.Helper;
import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.settings.KeyBinding;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -33,9 +31,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(KeyBinding.class) @Mixin(KeyBinding.class)
public class MixinKeyBinding { public class MixinKeyBinding {
@Shadow
private int pressTime;
@Inject( @Inject(
method = "isKeyDown", method = "isKeyDown",
at = @At("HEAD"), at = @At("HEAD"),
@@ -43,26 +38,8 @@ public class MixinKeyBinding {
) )
private void isKeyDown(CallbackInfoReturnable<Boolean> cir) { private void isKeyDown(CallbackInfoReturnable<Boolean> cir) {
// only the primary baritone forces keys // only the primary baritone forces keys
Boolean force = BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this); if (BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this)) {
if (force != null) { cir.setReturnValue(true);
cir.setReturnValue(force); // :sunglasses:
}
}
@Inject(
method = "isPressed",
at = @At("HEAD"),
cancellable = true
)
private void isPressed(CallbackInfoReturnable<Boolean> cir) {
// only the primary baritone forces keys
Boolean force = BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this);
if (force != null && !force) { // <-- cursed
if (pressTime > 0) {
Helper.HELPER.logDirect("You're trying to press this mouse button but I won't let you");
pressTime--;
}
cir.setReturnValue(force); // :sunglasses:
} }
} }
} }
@@ -96,6 +96,15 @@ public class MixinMinecraft {
} }
@Inject(
method = "processKeyBinds",
at = @At("HEAD")
)
private void runTickKeyboard(CallbackInfo ci) {
// keyboard input is only the primary baritone
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onProcessKeyBinds();
}
@Inject( @Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("HEAD") at = @At("HEAD")
@@ -155,7 +164,7 @@ public class MixinMinecraft {
) )
private void onBlockBreak(CallbackInfo ci, BlockPos pos) { private void onBlockBreak(CallbackInfo ci, BlockPos pos) {
// clickMouse is only for the main player // clickMouse is only for the main player
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.START_BREAK)); BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.BREAK));
} }
@Inject( @Inject(
+33 -27
View File
@@ -74,6 +74,7 @@ public class Baritone implements IBaritone {
private GameEventHandler gameEventHandler; private GameEventHandler gameEventHandler;
private List<Behavior> behaviors; private List<Behavior> behaviors;
private ControllerBehavior controllerBehavior;
private PathingBehavior pathingBehavior; private PathingBehavior pathingBehavior;
private LookBehavior lookBehavior; private LookBehavior lookBehavior;
private MemoryBehavior memoryBehavior; private MemoryBehavior memoryBehavior;
@@ -104,10 +105,10 @@ public class Baritone implements IBaritone {
this.behaviors = new ArrayList<>(); this.behaviors = new ArrayList<>();
{ {
// the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist // the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist
controllerBehavior = new ControllerBehavior(this);
pathingBehavior = new PathingBehavior(this); pathingBehavior = new PathingBehavior(this);
lookBehavior = new LookBehavior(this); lookBehavior = new LookBehavior(this);
memoryBehavior = new MemoryBehavior(this); memoryBehavior = new MemoryBehavior(this);
new InventoryBehavior(this);
inputOverrideHandler = new InputOverrideHandler(this); inputOverrideHandler = new InputOverrideHandler(this);
new ExampleBaritoneControl(this); new ExampleBaritoneControl(this);
} }
@@ -129,11 +130,6 @@ public class Baritone implements IBaritone {
this.initialized = true; this.initialized = true;
} }
@Override
public PathingControlManager getPathingControlManager() {
return this.pathingControlManager;
}
public List<Behavior> getBehaviors() { public List<Behavior> getBehaviors() {
return this.behaviors; return this.behaviors;
} }
@@ -143,11 +139,20 @@ public class Baritone implements IBaritone {
this.gameEventHandler.registerEventListener(behavior); this.gameEventHandler.registerEventListener(behavior);
} }
@Override
public PathingControlManager getPathingControlManager() {
return this.pathingControlManager;
}
@Override @Override
public InputOverrideHandler getInputOverrideHandler() { public InputOverrideHandler getInputOverrideHandler() {
return this.inputOverrideHandler; return this.inputOverrideHandler;
} }
public ControllerBehavior getControllerBehavior() {
return this.controllerBehavior;
}
@Override @Override
public CustomGoalProcess getCustomGoalProcess() { // Iffy public CustomGoalProcess getCustomGoalProcess() { // Iffy
return this.customGoalProcess; return this.customGoalProcess;
@@ -159,34 +164,25 @@ public class Baritone implements IBaritone {
} }
@Override @Override
public IPlayerContext getPlayerContext() { public PathingBehavior getPathingBehavior() {
return this.playerContext; return this.pathingBehavior;
} }
@Override
public MemoryBehavior getMemoryBehavior() { public MemoryBehavior getMemoryBehavior() {
return this.memoryBehavior; return this.memoryBehavior;
} }
@Override
public IPlayerContext getPlayerContext() {
return this.playerContext;
}
@Override @Override
public FollowProcess getFollowProcess() { public FollowProcess getFollowProcess() {
return this.followProcess; return this.followProcess;
} }
@Override
public LookBehavior getLookBehavior() {
return this.lookBehavior;
}
@Override
public MineProcess getMineProcess() {
return this.mineProcess;
}
@Override
public PathingBehavior getPathingBehavior() {
return this.pathingBehavior;
}
@Override @Override
public WorldProvider getWorldProvider() { public WorldProvider getWorldProvider() {
return this.worldProvider; return this.worldProvider;
@@ -197,6 +193,20 @@ public class Baritone implements IBaritone {
return this.gameEventHandler; return this.gameEventHandler;
} }
@Override
public LookBehavior getLookBehavior() {
return this.lookBehavior;
}
@Override
public MineProcess getMineProcess() {
return this.mineProcess;
}
public static Executor getExecutor() {
return threadPool;
}
public static Settings settings() { public static Settings settings() {
return BaritoneAPI.getSettings(); return BaritoneAPI.getSettings();
} }
@@ -204,8 +214,4 @@ public class Baritone implements IBaritone {
public static File getDir() { public static File getDir() {
return dir; return dir;
} }
public static Executor getExecutor() {
return threadPool;
}
} }
@@ -0,0 +1,163 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.behavior;
import baritone.Baritone;
import baritone.api.event.events.ChatEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.process.IBaritoneProcess;
import baritone.api.utils.BetterBlockPos;
import baritone.pathing.movement.CalculationContext;
import baritone.utils.Helper;
import baritone.utils.pathing.SegmentedCalculator;
import cabaletta.comms.BufferedConnection;
import cabaletta.comms.IConnection;
import cabaletta.comms.IMessageListener;
import cabaletta.comms.downward.MessageChat;
import cabaletta.comms.downward.MessageComputationRequest;
import cabaletta.comms.iMessage;
import cabaletta.comms.upward.MessageComputationResponse;
import cabaletta.comms.upward.MessageStatus;
import net.minecraft.util.math.BlockPos;
import java.io.IOException;
import java.util.Objects;
public class ControllerBehavior extends Behavior implements IMessageListener {
public ControllerBehavior(Baritone baritone) {
super(baritone);
}
private BufferedConnection conn;
@Override
public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
return;
}
trySend(buildStatus());
readAndHandle();
}
public MessageStatus buildStatus() {
// TODO report inventory and echest contents
// TODO figure out who should remember echest contents when it isn't open, baritone or tenor?
BlockPos pathStart = baritone.getPathingBehavior().pathStart();
return new MessageStatus(
ctx.player().posX,
ctx.player().posY,
ctx.player().posZ,
ctx.player().rotationYaw,
ctx.player().rotationPitch,
ctx.player().onGround,
ctx.player().getHealth(),
ctx.player().getFoodStats().getSaturationLevel(),
ctx.player().getFoodStats().getFoodLevel(),
pathStart.getX(),
pathStart.getY(),
pathStart.getZ(),
baritone.getPathingBehavior().getCurrent() != null,
baritone.getPathingBehavior().getNext() != null,
baritone.getPathingBehavior().getInProgress().isPresent(),
baritone.getPathingBehavior().ticksRemainingInSegment().orElse(0D),
baritone.getPathingBehavior().calcFailedLastTick(),
baritone.getPathingBehavior().isSafeToCancel(),
baritone.getPathingBehavior().getGoal() + "",
baritone.getPathingControlManager().mostRecentInControl().map(IBaritoneProcess::displayName).orElse("")
);
}
private void readAndHandle() {
if (conn == null) {
return;
}
try {
conn.handleAllPendingMessages(this);
} catch (IOException e) {
e.printStackTrace();
disconnect();
}
}
public boolean trySend(iMessage msg) {
if (conn == null) {
return false;
}
try {
conn.sendMessage(msg);
return true;
} catch (IOException e) {
e.printStackTrace();
disconnect();
return false;
}
}
public void connectTo(IConnection conn) {
disconnect();
this.conn = BufferedConnection.makeBuffered(conn);
}
public void disconnect() {
if (conn != null) {
conn.close();
}
conn = null;
}
@Override
public void handle(MessageChat msg) { // big brain
ChatEvent event = new ChatEvent(ctx.player(), msg.msg);
baritone.getGameEventHandler().onSendChatMessage(event);
}
@Override
public void handle(MessageComputationRequest msg) {
BetterBlockPos start = new BetterBlockPos(msg.startX, msg.startY, msg.startZ);
// TODO this may require scanning the world for blocks of a certain type, idk how to manage that
Goal goal = new GoalYLevel(Integer.parseInt(msg.goal)); // im already winston
SegmentedCalculator.calculateSegmentsThreaded(start, goal, new CalculationContext(baritone), path -> {
if (!Objects.equals(path.getGoal(), goal)) {
throw new IllegalStateException(); // sanity check
}
try {
BetterBlockPos dest = path.getDest();
conn.sendMessage(new MessageComputationResponse(msg.computationID, path.length(), path.totalTicks(), path.getGoal().isInGoal(dest), dest.x, dest.y, dest.z));
} catch (IOException e) {
// nothing we can do about this, we just completed a computation but our tenor connection was closed in the meantime
// just discard the path we made for them =((
e.printStackTrace(); // and complain =)
}
}, () -> {
try {
conn.sendMessage(new MessageComputationResponse(msg.computationID, 0, 0, false, 0, 0, 0));
} catch (IOException e) {
// same deal
e.printStackTrace();
}
});
}
@Override
public void unhandled(iMessage msg) {
Helper.HELPER.logDebug("Unhandled message received by ControllerBehavior " + msg);
}
}
@@ -1,90 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.behavior;
import baritone.Baritone;
import baritone.api.event.events.TickEvent;
import baritone.utils.ToolSet;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ClickType;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemTool;
import net.minecraft.util.NonNullList;
public class InventoryBehavior extends Behavior {
public InventoryBehavior(Baritone baritone) {
super(baritone);
}
@Override
public void onTick(TickEvent event) {
if (!Baritone.settings().allowInventory.get()) {
return;
}
if (event.getType() == TickEvent.Type.OUT) {
return;
}
if (ctx.player().openContainer != ctx.player().inventoryContainer) {
// we have a crafting table or a chest or something open
return;
}
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
swapWithHotBar(firstValidThrowaway(), 8);
}
int pick = bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
if (pick >= 9) {
swapWithHotBar(pick, 0);
}
}
private void swapWithHotBar(int inInventory, int inHotbar) {
ctx.playerController().windowClick(ctx.player().inventoryContainer.windowId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player());
}
private int firstValidThrowaway() { // TODO offhand idk
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
for (int i = 0; i < invy.size(); i++) {
if (Baritone.settings().acceptableThrowawayItems.get().contains(invy.get(i).getItem())) {
return i;
}
}
return -1;
}
private int bestToolAgainst(Block against, Class<? extends ItemTool> klass) {
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
int bestInd = -1;
double bestSpeed = -1;
for (int i = 0; i < invy.size(); i++) {
ItemStack stack = invy.get(i);
if (stack.isEmpty()) {
continue;
}
if (klass.isInstance(stack.getItem())) {
double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants
if (speed > bestSpeed) {
bestSpeed = speed;
bestInd = i;
}
}
}
return bestInd;
}
}
@@ -95,12 +95,6 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
} }
} }
public void pig() {
if (this.target != null) {
ctx.player().rotationYaw = this.target.getYaw();
}
}
@Override @Override
public void onPlayerRotationMove(RotationMoveEvent event) { public void onPlayerRotationMove(RotationMoveEvent event) {
if (this.target != null && !this.force) { if (this.target != null && !this.force) {
@@ -18,18 +18,16 @@
package baritone.behavior; package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.behavior.IMemoryBehavior;
import baritone.api.behavior.memory.IRememberedInventory;
import baritone.api.cache.IWorldData;
import baritone.api.event.events.BlockInteractEvent; import baritone.api.event.events.BlockInteractEvent;
import baritone.api.event.events.PacketEvent; import baritone.api.event.events.PacketEvent;
import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.type.EventState; import baritone.api.event.events.type.EventState;
import baritone.cache.ContainerMemory;
import baritone.cache.Waypoint; import baritone.cache.Waypoint;
import baritone.pathing.movement.CalculationContext;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBed; import net.minecraft.block.BlockBed;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
import net.minecraft.network.play.client.CPacketCloseWindow; import net.minecraft.network.play.client.CPacketCloseWindow;
@@ -38,39 +36,22 @@ import net.minecraft.network.play.server.SPacketCloseWindow;
import net.minecraft.network.play.server.SPacketOpenWindow; import net.minecraft.network.play.server.SPacketOpenWindow;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityLockable; import net.minecraft.tileentity.TileEntityLockable;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
/** /**
* doesn't work for horse inventories :^)
*
* @author Brady * @author Brady
* @since 8/6/2018 * @since 8/6/2018
*/ */
public final class MemoryBehavior extends Behavior { public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
private final List<FutureInventory> futureInventories = new ArrayList<>(); // this is per-bot private final Map<IWorldData, WorldDataContainer> worldDataContainers = new HashMap<>();
private Integer enderChestWindowId; // nae nae
public MemoryBehavior(Baritone baritone) { public MemoryBehavior(Baritone baritone) {
super(baritone); super(baritone);
} }
@Override
public synchronized void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
enderChestWindowId = null;
futureInventories.clear();
}
}
@Override @Override
public synchronized void onPlayerUpdate(PlayerUpdateEvent event) { public synchronized void onPlayerUpdate(PlayerUpdateEvent event) {
if (event.getState() == EventState.PRE) { if (event.getState() == EventState.PRE) {
@@ -87,29 +68,19 @@ public final class MemoryBehavior extends Behavior {
CPacketPlayerTryUseItemOnBlock packet = event.cast(); CPacketPlayerTryUseItemOnBlock packet = event.cast();
TileEntity tileEntity = ctx.world().getTileEntity(packet.getPos()); TileEntity tileEntity = ctx.world().getTileEntity(packet.getPos());
// if tileEntity is an ender chest, we don't need to do anything. ender chests are treated the same regardless of what coordinate right clicked
// Ensure the TileEntity is a container of some sort // Ensure the TileEntity is a container of some sort
if (tileEntity instanceof TileEntityLockable) { if (tileEntity instanceof TileEntityLockable) {
TileEntityLockable lockable = (TileEntityLockable) tileEntity; TileEntityLockable lockable = (TileEntityLockable) tileEntity;
int size = lockable.getSizeInventory(); int size = lockable.getSizeInventory();
BlockPos position = tileEntity.getPos();
BlockPos adj = neighboringConnectedBlock(position);
System.out.println(position + " " + adj);
if (adj != null) {
size *= 2; // double chest or double trapped chest
if (adj.getX() < position.getX() || adj.getZ() < position.getZ()) {
position = adj; // standardize on the lower coordinate, regardless of which side of the large chest we right clicked
}
}
this.futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), position)); this.getCurrentContainer().futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), tileEntity.getPos()));
} }
} }
if (p instanceof CPacketCloseWindow) { if (p instanceof CPacketCloseWindow) {
getCurrent().save(); updateInventory();
} }
} }
} }
@@ -121,29 +92,27 @@ public final class MemoryBehavior extends Behavior {
if (event.getState() == EventState.PRE) { if (event.getState() == EventState.PRE) {
if (p instanceof SPacketOpenWindow) { if (p instanceof SPacketOpenWindow) {
SPacketOpenWindow packet = event.cast(); SPacketOpenWindow packet = event.cast();
// Remove any entries that were created over a second ago, this should make up for INSANE latency
futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
System.out.println("Received packet " + packet.getGuiId() + " " + packet.getEntityId() + " " + packet.getSlotCount() + " " + packet.getWindowId()); WorldDataContainer container = this.getCurrentContainer();
System.out.println(packet.getWindowTitle());
if (packet.getWindowTitle() instanceof TextComponentTranslation && ((TextComponentTranslation) packet.getWindowTitle()).getKey().equals("container.enderchest")) { // Remove any entries that were created over a second ago, this should make up for INSANE latency
// title is not customized (i.e. this isn't just a renamed shulker) container.futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
enderChestWindowId = packet.getWindowId();
return; container.futureInventories.stream()
}
futureInventories.stream()
.filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount()) .filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount())
.findFirst().ifPresent(matched -> { .findFirst().ifPresent(matched -> {
// Remove the future inventory // Remove the future inventory
futureInventories.remove(matched); container.futureInventories.remove(matched);
// Setup the remembered inventory // Setup the remembered inventory
getCurrentContainer().setup(matched.pos, packet.getWindowId(), packet.getSlotCount()); RememberedInventory inventory = container.rememberedInventories.computeIfAbsent(matched.pos, pos -> new RememberedInventory());
inventory.windowId = packet.getWindowId();
inventory.size = packet.getSlotCount();
}); });
} }
if (p instanceof SPacketCloseWindow) { if (p instanceof SPacketCloseWindow) {
getCurrent().save(); updateInventory();
} }
} }
} }
@@ -160,42 +129,43 @@ public final class MemoryBehavior extends Behavior {
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet())); baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet()));
} }
private Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
return this.getCurrentContainer().rememberedInventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
}
private void updateInventory() { private void updateInventory() {
int windowId = ctx.player().openContainer.windowId; getInventoryFromWindow(ctx.player().openContainer.windowId).ifPresent(inventory -> {
if (enderChestWindowId != null) { inventory.items.clear();
if (windowId == enderChestWindowId) { inventory.items.addAll(ctx.player().openContainer.getInventory().subList(0, inventory.size));
getCurrent().contents = ctx.player().openContainer.getInventory().subList(0, 27); });
} else {
getCurrent().save();
enderChestWindowId = null;
}
}
if (getCurrentContainer() != null) {
getCurrentContainer().getInventoryFromWindow(windowId).ifPresent(inventory -> inventory.updateFromOpenWindow(ctx));
}
} }
private ContainerMemory getCurrentContainer() { private WorldDataContainer getCurrentContainer() {
if (baritone.getWorldProvider().getCurrentWorld() == null) { return this.worldDataContainers.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), data -> new WorldDataContainer());
return null;
}
return (ContainerMemory) baritone.getWorldProvider().getCurrentWorld().getContainerMemory();
} }
private BlockPos neighboringConnectedBlock(BlockPos in) { @Override
BlockStateInterface bsi = new CalculationContext(baritone).bsi; public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
Block block = bsi.get0(in).getBlock(); return this.getCurrentContainer().rememberedInventories.get(pos);
if (block != Blocks.TRAPPED_CHEST && block != Blocks.CHEST) { }
return null; // other things that have contents, but can be placed adjacent without combining
} @Override
for (int i = 0; i < 4; i++) { public final synchronized Map<BlockPos, IRememberedInventory> getRememberedInventories() {
BlockPos adj = in.offset(EnumFacing.byHorizontalIndex(i)); // make a copy since this map is modified from the packet thread
if (bsi.get0(adj).getBlock() == block) { return new HashMap<>(this.getCurrentContainer().rememberedInventories);
return adj; }
}
} private static final class WorldDataContainer {
return null;
/**
* Possible future inventories that we will be able to remember
*/
private final List<FutureInventory> futureInventories = new ArrayList<>();
/**
* The current remembered inventories
*/
private final Map<BlockPos, RememberedInventory> rememberedInventories = new HashMap<>();
} }
/** /**
@@ -228,51 +198,43 @@ public final class MemoryBehavior extends Behavior {
this.slots = slots; this.slots = slots;
this.type = type; this.type = type;
this.pos = pos; this.pos = pos;
System.out.println("Future inventory created " + time + " " + slots + " " + type + " " + pos);
} }
} }
public Optional<List<ItemStack>> echest() { /**
return Optional.ofNullable(getCurrent().contents).map(Collections::unmodifiableList); * An inventory that we are aware of.
} * <p>
* Associated with a {@link BlockPos} in {@link WorldDataContainer#rememberedInventories}.
*/
public static class RememberedInventory implements IRememberedInventory {
public EnderChestMemory getCurrent() { /**
Path path = baritone.getWorldProvider().getCurrentWorld().directory; * The list of items in the inventory
return EnderChestMemory.getByServerAndPlayer(path.getParent(), ctx.player().getUniqueID()); */
} private final List<ItemStack> items;
public static class EnderChestMemory { /**
private static final Map<Path, EnderChestMemory> memory = new HashMap<>(); * The last known window ID of the inventory
private final Path enderChest; */
private List<ItemStack> contents; private int windowId;
private EnderChestMemory(Path enderChest) { /**
this.enderChest = enderChest; * The size of the inventory
System.out.println("Echest storing in " + enderChest); */
try { private int size;
this.contents = ContainerMemory.readItemStacks(Files.readAllBytes(enderChest));
} catch (IOException e) { private RememberedInventory() {
e.printStackTrace(); this.items = new ArrayList<>();
System.out.println("CANNOT read echest =( =(");
this.contents = null;
}
} }
public synchronized void save() { @Override
System.out.println("Saving"); public final List<ItemStack> getContents() {
if (contents != null) { return Collections.unmodifiableList(this.items);
try {
enderChest.getParent().toFile().mkdir();
Files.write(enderChest, ContainerMemory.writeItemStacks(contents));
} catch (IOException e) {
e.printStackTrace();
System.out.println("CANNOT save echest =( =(");
}
}
} }
private static synchronized EnderChestMemory getByServerAndPlayer(Path serverStorage, UUID player) { @Override
return memory.computeIfAbsent(serverStorage.resolve("echests").resolve(player.toString()), EnderChestMemory::new); public final int getSize() {
return this.size;
} }
} }
} }
@@ -19,7 +19,10 @@ package baritone.behavior;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.behavior.IPathingBehavior; import baritone.api.behavior.IPathingBehavior;
import baritone.api.event.events.*; import baritone.api.event.events.PathEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RenderEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalXZ; import baritone.api.pathing.goals.GoalXZ;
@@ -30,17 +33,16 @@ import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.CutoffPath;
import baritone.pathing.path.PathExecutor; import baritone.pathing.path.PathExecutor;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.PathRenderer; import baritone.utils.PathRenderer;
import baritone.utils.pathing.Favoring;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper { public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper {
@@ -93,13 +95,6 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
dispatchEvents(); dispatchEvents();
} }
@Override
public void onPlayerSprintState(SprintStateEvent event) {
if (current != null) {
event.setState(current.isSprinting());
}
}
private void tickPath() { private void tickPath() {
if (pauseRequestedLastTick && safeToCancel) { if (pauseRequestedLastTick && safeToCancel) {
pauseRequestedLastTick = false; pauseRequestedLastTick = false;
@@ -124,7 +119,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
next = null; next = null;
return; return;
} }
if (next != null && !next.getPath().positions().contains(ctx.playerFeet()) && !next.getPath().positions().contains(pathStart())) { // can contain either one if (next != null && !next.getPath().positions().contains(ctx.playerFeet())) {
// if the current path failed, we may not actually be on the next one, so make sure // if the current path failed, we may not actually be on the next one, so make sure
logDebug("Discarding next path as it does not contain current position"); logDebug("Discarding next path as it does not contain current position");
// for example if we had a nicely planned ahead path that starts where current ends // for example if we had a nicely planned ahead path that starts where current ends
@@ -140,27 +135,16 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
queuePathEvent(PathEvent.CONTINUING_ONTO_PLANNED_NEXT); queuePathEvent(PathEvent.CONTINUING_ONTO_PLANNED_NEXT);
current = next; current = next;
next = null; next = null;
current.onTick(); // don't waste a tick doing nothing, get started right away current.onTick();
return; return;
} }
// at this point, current just ended, but we aren't in the goal and have no plan for the future // at this point, current just ended, but we aren't in the goal and have no plan for the future
synchronized (pathCalcLock) { synchronized (pathCalcLock) {
if (inProgress != null) { if (inProgress != null) {
// we are calculating queuePathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING);
// are we calculating the right thing though? 🤔 // if we aren't calculating right now
BetterBlockPos calcFrom = inProgress.getStart(); return;
// if current just succeeded, we should be standing in calcFrom, so that's cool and good
// but if current just failed, we should discard this calculation since it doesn't start from where we're standing
if (calcFrom.equals(ctx.playerFeet()) || calcFrom.equals(pathStart())) {
// cool and good
queuePathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING);
return;
}
// oh noes
inProgress.cancel(); // cancellation doesn't dispatch any events
inProgress = null; // this is safe since we hold both locks
} }
// we aren't calculating
queuePathEvent(PathEvent.CALC_STARTED); queuePathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true); findPathInNewThread(pathStart(), true);
} }
@@ -190,11 +174,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
return; return;
} }
if (goal == null || goal.isInGoal(current.getPath().getDest())) { if (goal == null || goal.isInGoal(current.getPath().getDest())) {
// and this path doesn't get us all the way there // and this path dosen't get us all the way there
return; return;
} }
if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) { if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) {
// and this path has 7.5 seconds or less left // and this path has 5 seconds or less left
logDebug("Path almost over. Planning ahead..."); logDebug("Path almost over. Planning ahead...");
queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED); queuePathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED);
findPathInNewThread(current.getPath().getDest(), false); findPathInNewThread(current.getPath().getDest(), false);
@@ -220,6 +204,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} }
} }
@Override
public Optional<Double> ticksRemainingInSegment() {
if (current == null) {
return Optional.empty();
}
return Optional.of(current.getPath().ticksRemainingFrom(current.getPosition()));
}
public void secretInternalSetGoal(Goal goal) { public void secretInternalSetGoal(Goal goal) {
this.goal = goal; this.goal = goal;
} }
@@ -249,6 +241,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
return Optional.ofNullable(inProgress); return Optional.ofNullable(inProgress);
} }
@Override
public boolean isPathing() {
return this.current != null;
}
public boolean isSafeToCancel() { public boolean isSafeToCancel() {
return current == null || safeToCancel; return current == null || safeToCancel;
} }
@@ -271,7 +268,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (doIt) { if (doIt) {
secretInternalSegmentCancel(); secretInternalSegmentCancel();
} }
baritone.getPathingControlManager().cancelEverything(); // regardless of if we can stop the current segment, we can still stop the processes baritone.getPathingControlManager().cancelEverything();
return doIt; return doIt;
} }
@@ -280,13 +277,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} }
public void softCancelIfSafe() { public void softCancelIfSafe() {
synchronized (pathPlanLock) { if (!isSafeToCancel()) {
if (!isSafeToCancel()) { return;
return;
}
current = null;
next = null;
} }
current = null;
next = null;
cancelRequested = true; cancelRequested = true;
getInProgress().ifPresent(AbstractNodeCostSearch::cancel); // only cancel ours getInProgress().ifPresent(AbstractNodeCostSearch::cancel); // only cancel ours
// do everything BUT clear keys // do everything BUT clear keys
@@ -295,10 +290,8 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
// just cancel the current path // just cancel the current path
public void secretInternalSegmentCancel() { public void secretInternalSegmentCancel() {
queuePathEvent(PathEvent.CANCELED); queuePathEvent(PathEvent.CANCELED);
synchronized (pathPlanLock) { current = null;
current = null; next = null;
next = null;
}
baritone.getInputOverrideHandler().clearAllKeys(); baritone.getInputOverrideHandler().clearAllKeys();
getInProgress().ifPresent(AbstractNodeCostSearch::cancel); getInProgress().ifPresent(AbstractNodeCostSearch::cancel);
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock(); baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
@@ -307,9 +300,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
public void forceCancel() { // NOT exposed on public api public void forceCancel() { // NOT exposed on public api
cancelEverything(); cancelEverything();
secretInternalSegmentCancel(); secretInternalSegmentCancel();
synchronized (pathCalcLock) { inProgress = null;
inProgress = null;
}
} }
/** /**
@@ -339,18 +330,12 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} }
} }
public void secretCursedFunctionDoNotCall(IPath path) {
synchronized (pathPlanLock) {
current = new PathExecutor(this, path);
}
}
/** /**
* See issue #209 * See issue #209
* *
* @return The starting {@link BlockPos} for a new path * @return The starting {@link BlockPos} for a new path
*/ */
public BetterBlockPos pathStart() { // TODO move to a helper or util class public BlockPos pathStart() { // TODO move to a helper or util class
BetterBlockPos feet = ctx.playerFeet(); BetterBlockPos feet = ctx.playerFeet();
if (!MovementHelper.canWalkOn(ctx, feet.down())) { if (!MovementHelper.canWalkOn(ctx, feet.down())) {
if (ctx.player().onGround) { if (ctx.player().onGround) {
@@ -373,7 +358,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} }
if (MovementHelper.canWalkOn(ctx, possibleSupport.down()) && MovementHelper.canWalkThrough(ctx, possibleSupport) && MovementHelper.canWalkThrough(ctx, possibleSupport.up())) { if (MovementHelper.canWalkOn(ctx, possibleSupport.down()) && MovementHelper.canWalkThrough(ctx, possibleSupport) && MovementHelper.canWalkThrough(ctx, possibleSupport.up())) {
// this is plausible // this is plausible
logDebug("Faking path start assuming player is standing off the edge of a block"); //logDebug("Faking path start assuming player is standing off the edge of a block");
return possibleSupport; return possibleSupport;
} }
} }
@@ -382,7 +367,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
// !onGround // !onGround
// we're in the middle of a jump // we're in the middle of a jump
if (MovementHelper.canWalkOn(ctx, feet.down().down())) { if (MovementHelper.canWalkOn(ctx, feet.down().down())) {
logDebug("Faking path start assuming player is midair and falling"); //logDebug("Faking path start assuming player is midair and falling");
return feet.down(); return feet.down();
} }
} }
@@ -420,9 +405,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.get(); primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.get();
failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.get(); failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.get();
} }
CalculationContext context = new CalculationContext(baritone, true); // not safe to create on the other thread, it looks up a lot of stuff in minecraft CalculationContext context = new CalculationContext(baritone); // not safe to create on the other thread, it looks up a lot of stuff in minecraft
AbstractNodeCostSearch pathfinder = createPathfinder(start, goal, current == null ? null : current.getPath(), context); AbstractNodeCostSearch pathfinder = createPathfinder(start, goal, current == null ? null : current.getPath(), context);
if (!Objects.equals(pathfinder.getGoal(), goal)) { // will return the exact same object if simplification didn't happen if (!Objects.equals(pathfinder.getGoal(), goal)) {
logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance"); logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance");
} }
inProgress = pathfinder; inProgress = pathfinder;
@@ -432,8 +417,33 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} }
PathCalculationResult calcResult = pathfinder.calculate(primaryTimeout, failureTimeout); PathCalculationResult calcResult = pathfinder.calculate(primaryTimeout, failureTimeout);
Optional<IPath> path = calcResult.getPath();
if (Baritone.settings().cutoffAtLoadBoundary.get()) {
path = path.map(p -> {
IPath result = p.cutoffAtLoadedChunks(context.world());
if (result instanceof CutoffPath) {
logDebug("Cutting off path at edge of loaded chunks");
logDebug("Length decreased by " + (p.length() - result.length()));
} else {
logDebug("Path ends within loaded chunks");
}
return result;
});
}
Optional<PathExecutor> executor = path.map(p -> {
IPath result = p.staticCutoff(goal);
if (result instanceof CutoffPath) {
logDebug("Static cutoff " + p.length() + " to " + result.length());
}
return result;
}).map(p -> new PathExecutor(this, p));
synchronized (pathPlanLock) { synchronized (pathPlanLock) {
Optional<PathExecutor> executor = calcResult.getPath().map(p -> new PathExecutor(PathingBehavior.this, p));
if (current == null) { if (current == null) {
if (executor.isPresent()) { if (executor.isPresent()) {
queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING); queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING);
@@ -453,9 +463,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
queuePathEvent(PathEvent.NEXT_CALC_FAILED); queuePathEvent(PathEvent.NEXT_CALC_FAILED);
} }
} else { } else {
//throw new IllegalStateException("I have no idea what to do with this path"); throw new IllegalStateException("I have no idea what to do with this path");
// no point in throwing an exception here, and it gets it stuck with inProgress being not null
logDirect("Warning: PathingBehaivor illegal state! Discarding invalid path!");
} }
} }
if (talkAboutIt && current != null && current.getPath() != null) { if (talkAboutIt && current != null && current.getPath() != null) {
@@ -476,12 +484,15 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
Goal transformed = goal; Goal transformed = goal;
if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) { if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) {
BlockPos pos = ((IGoalRenderPos) goal).getGoalPos(); BlockPos pos = ((IGoalRenderPos) goal).getGoalPos();
if (!context.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ())) { if (context.world().getChunk(pos) instanceof EmptyChunk) {
transformed = new GoalXZ(pos.getX(), pos.getZ()); transformed = new GoalXZ(pos.getX(), pos.getZ());
} }
} }
Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous); HashSet<Long> favoredPositions = null;
return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoring, context); if (Baritone.settings().backtrackCostFavoringCoefficient.get() != 1D && previous != null) {
favoredPositions = previous.positions().stream().map(BetterBlockPos::longHash).collect(Collectors.toCollection(HashSet::new));
}
return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoredPositions, context);
} }
@Override @Override
+1 -1
View File
@@ -35,7 +35,7 @@ public final class CachedChunk {
static { static {
HashSet<Block> temp = new HashSet<>(); HashSet<Block> temp = new HashSet<>();
//temp.add(Blocks.DIAMOND_ORE); temp.add(Blocks.DIAMOND_ORE);
temp.add(Blocks.DIAMOND_BLOCK); temp.add(Blocks.DIAMOND_BLOCK);
//temp.add(Blocks.COAL_ORE); //temp.add(Blocks.COAL_ORE);
temp.add(Blocks.COAL_BLOCK); temp.add(Blocks.COAL_BLOCK);
+3 -7
View File
@@ -179,8 +179,8 @@ public final class CachedWorld implements ICachedWorld, Helper {
if (region == null) { if (region == null) {
continue; continue;
} }
int distX = (region.getX() << 9 + 256) - pruneCenter.getX(); int distX = (region.getX() * 512 + 256) - pruneCenter.getX();
int distZ = (region.getZ() << 9 + 256) - pruneCenter.getZ(); int distZ = (region.getZ() * 512 + 256) - pruneCenter.getZ();
double dist = Math.sqrt(distX * distX + distZ * distZ); double dist = Math.sqrt(distX * distX + distZ * distZ);
if (dist > 1024) { if (dist > 1024) {
logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram"); logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram");
@@ -215,7 +215,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
if (mostRecentlyModified == null) { if (mostRecentlyModified == null) {
return new BlockPos(0, 0, 0); return new BlockPos(0, 0, 0);
} }
return new BlockPos(mostRecentlyModified.x << 4 + 8, 0, mostRecentlyModified.z << 4 + 8); return new BlockPos(mostRecentlyModified.x * 16 + 8, 0, mostRecentlyModified.z * 16 + 8);
} }
private synchronized List<CachedRegion> allRegions() { private synchronized List<CachedRegion> allRegions() {
@@ -255,10 +255,6 @@ public final class CachedWorld implements ICachedWorld, Helper {
}); });
} }
public void tryLoadFromDisk(int regionX, int regionZ) {
getOrCreateRegion(regionX, regionZ);
}
/** /**
* Returns the region ID based on the region coordinates. 0 will be * Returns the region ID based on the region coordinates. 0 will be
* returned if the specified region coordinates are out of bounds. * returned if the specified region coordinates are out of bounds.
+5 -4
View File
@@ -39,8 +39,6 @@ import java.util.*;
*/ */
public final class ChunkPacker { public final class ChunkPacker {
private static final Map<String, Block> resourceCache = new HashMap<>();
private ChunkPacker() {} private ChunkPacker() {}
public static CachedChunk pack(Chunk chunk) { public static CachedChunk pack(Chunk chunk) {
@@ -93,7 +91,10 @@ public final class ChunkPacker {
IBlockState[] blocks = new IBlockState[256]; IBlockState[] blocks = new IBlockState[256];
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html // @formatter:off
https:
//www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html
// @formatter:on
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
for (int y = 255; y >= 0; y--) { for (int y = 255; y >= 0; y--) {
int index = CachedChunk.getPositionIndex(x, y, z); int index = CachedChunk.getPositionIndex(x, y, z);
@@ -119,7 +120,7 @@ public final class ChunkPacker {
} }
public static Block stringToBlock(String name) { public static Block stringToBlock(String name) {
return resourceCache.computeIfAbsent(name, n -> Block.getBlockFromName(n.contains(":") ? n : "minecraft:" + n)); return Block.getBlockFromName(name.contains(":") ? name : "minecraft:" + name);
} }
private static PathingBlockType getPathingBlockType(IBlockState state) { private static PathingBlockType getPathingBlockType(IBlockState state) {
-176
View File
@@ -1,176 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.cache;
import baritone.api.cache.IContainerMemory;
import baritone.api.cache.IRememberedInventory;
import baritone.api.utils.IPlayerContext;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ContainerMemory implements IContainerMemory {
private final Path saveTo;
/**
* The current remembered inventories
*/
private final Map<BlockPos, RememberedInventory> inventories = new HashMap<>();
public ContainerMemory(Path saveTo) {
this.saveTo = saveTo;
try {
read(Files.readAllBytes(saveTo));
} catch (Exception ex) {
ex.printStackTrace();
inventories.clear();
}
}
private void read(byte[] bytes) throws IOException {
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
int chests = in.readInt();
for (int i = 0; i < chests; i++) {
int x = in.readInt();
int y = in.readInt();
int z = in.readInt();
RememberedInventory rem = new RememberedInventory();
rem.items.addAll(readItemStacks(in));
rem.size = rem.items.size();
rem.windowId = -1;
if (rem.items.isEmpty()) {
continue; // this only happens if the list has no elements, not if the list has elements that are all empty item stacks
}
inventories.put(new BlockPos(x, y, z), rem);
}
}
public synchronized void save() throws IOException {
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
PacketBuffer out = new PacketBuffer(buf);
out.writeInt(inventories.size());
for (Map.Entry<BlockPos, RememberedInventory> entry : inventories.entrySet()) {
out = new PacketBuffer(out.writeInt(entry.getKey().getX()));
out = new PacketBuffer(out.writeInt(entry.getKey().getY()));
out = new PacketBuffer(out.writeInt(entry.getKey().getZ()));
out = writeItemStacks(entry.getValue().getContents(), out);
}
Files.write(saveTo, out.array());
}
public synchronized void setup(BlockPos pos, int windowId, int slotCount) {
RememberedInventory inventory = inventories.computeIfAbsent(pos, x -> new RememberedInventory());
inventory.windowId = windowId;
inventory.size = slotCount;
}
public synchronized Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
return inventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
}
@Override
public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
return inventories.get(pos);
}
@Override
public final synchronized Map<BlockPos, IRememberedInventory> getRememberedInventories() {
// make a copy since this map is modified from the packet thread
return new HashMap<>(inventories);
}
public static List<ItemStack> readItemStacks(byte[] bytes) throws IOException {
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
return readItemStacks(in);
}
public static List<ItemStack> readItemStacks(PacketBuffer in) throws IOException {
int count = in.readInt();
List<ItemStack> result = new ArrayList<>();
for (int i = 0; i < count; i++) {
result.add(in.readItemStack());
}
return result;
}
public static byte[] writeItemStacks(List<ItemStack> write) {
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
PacketBuffer out = new PacketBuffer(buf);
out = writeItemStacks(write, out);
return out.array();
}
public static PacketBuffer writeItemStacks(List<ItemStack> write, PacketBuffer out2) {
PacketBuffer out = out2; // avoid reassigning an argument LOL
out = new PacketBuffer(out.writeInt(write.size()));
for (ItemStack stack : write) {
out = out.writeItemStack(stack);
}
return out;
}
/**
* An inventory that we are aware of.
* <p>
* Associated with a {@link BlockPos} in {@link ContainerMemory#inventories}.
*/
public static class RememberedInventory implements IRememberedInventory {
/**
* The list of items in the inventory
*/
private final List<ItemStack> items;
/**
* The last known window ID of the inventory
*/
private int windowId;
/**
* The size of the inventory
*/
private int size;
private RememberedInventory() {
this.items = new ArrayList<>();
}
@Override
public final List<ItemStack> getContents() {
return Collections.unmodifiableList(this.items);
}
@Override
public final int getSize() {
return this.size;
}
public void updateFromOpenWindow(IPlayerContext ctx) {
items.clear();
items.addAll(ctx.player().openContainer.getInventory().subList(0, size));
}
}
}
@@ -32,7 +32,7 @@ import java.util.stream.Collectors;
* *
* @author leijurv * @author leijurv
*/ */
public class WaypointCollection implements IWaypointCollection { public class Waypoints implements IWaypointCollection {
/** /**
* Magic value to detect invalid waypoint files * Magic value to detect invalid waypoint files
@@ -42,7 +42,7 @@ public class WaypointCollection implements IWaypointCollection {
private final Path directory; private final Path directory;
private final Map<IWaypoint.Tag, Set<IWaypoint>> waypoints; private final Map<IWaypoint.Tag, Set<IWaypoint>> waypoints;
WaypointCollection(Path directory) { Waypoints(Path directory) {
this.directory = directory; this.directory = directory;
if (!Files.exists(directory)) { if (!Files.exists(directory)) {
try { try {
+2 -20
View File
@@ -19,11 +19,9 @@ package baritone.cache;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.cache.ICachedWorld; import baritone.api.cache.ICachedWorld;
import baritone.api.cache.IContainerMemory;
import baritone.api.cache.IWaypointCollection; import baritone.api.cache.IWaypointCollection;
import baritone.api.cache.IWorldData; import baritone.api.cache.IWorldData;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
/** /**
@@ -34,8 +32,7 @@ import java.nio.file.Path;
public class WorldData implements IWorldData { public class WorldData implements IWorldData {
public final CachedWorld cache; public final CachedWorld cache;
private final WaypointCollection waypoints; private final Waypoints waypoints;
private final ContainerMemory containerMemory;
//public final MapData map; //public final MapData map;
public final Path directory; public final Path directory;
public final int dimension; public final int dimension;
@@ -43,8 +40,7 @@ public class WorldData implements IWorldData {
WorldData(Path directory, int dimension) { WorldData(Path directory, int dimension) {
this.directory = directory; this.directory = directory;
this.cache = new CachedWorld(directory.resolve("cache"), dimension); this.cache = new CachedWorld(directory.resolve("cache"), dimension);
this.waypoints = new WaypointCollection(directory.resolve("waypoints")); this.waypoints = new Waypoints(directory.resolve("waypoints"));
this.containerMemory = new ContainerMemory(directory.resolve("containers"));
this.dimension = dimension; this.dimension = dimension;
} }
@@ -53,15 +49,6 @@ public class WorldData implements IWorldData {
System.out.println("Started saving the world in a new thread"); System.out.println("Started saving the world in a new thread");
cache.save(); cache.save();
}); });
Baritone.getExecutor().execute(() -> {
System.out.println("Started saving saved containers in a new thread");
try {
containerMemory.save();
} catch (IOException e) {
e.printStackTrace();
System.out.println("Failed to save saved containers");
}
});
} }
@Override @Override
@@ -73,9 +60,4 @@ public class WorldData implements IWorldData {
public IWaypointCollection getWaypoints() { public IWaypointCollection getWaypoints() {
return this.waypoints; return this.waypoints;
} }
@Override
public IContainerMemory getContainerMemory() {
return this.containerMemory;
}
} }
+2 -9
View File
@@ -24,7 +24,6 @@ import baritone.utils.accessor.IAnvilChunkLoader;
import baritone.utils.accessor.IChunkProviderServer; import baritone.utils.accessor.IChunkProviderServer;
import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
import org.apache.commons.lang3.SystemUtils;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -77,11 +76,7 @@ public class WorldProvider implements IWorldProvider, Helper {
directory = new File(directory, "baritone"); directory = new File(directory, "baritone");
readme = directory; readme = directory;
} else { // Otherwise, the server must be remote... } else { // Otherwise, the server must be remote...
String folderName = mc.getCurrentServerData().serverIP; directory = new File(Baritone.getDir(), mc.getCurrentServerData().serverIP);
if (SystemUtils.IS_OS_WINDOWS) {
folderName = folderName.replace(":", "_");
}
directory = new File(Baritone.getDir(), folderName);
readme = Baritone.getDir(); readme = Baritone.getDir();
} }
@@ -100,9 +95,7 @@ public class WorldProvider implements IWorldProvider, Helper {
} }
System.out.println("Baritone world data dir: " + dir); System.out.println("Baritone world data dir: " + dir);
synchronized (worldCache) { this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension));
this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension));
}
} }
public final void closeWorld() { public final void closeWorld() {
+29 -53
View File
@@ -23,14 +23,11 @@ import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.BlockStateContainer; import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import java.util.ArrayList; import java.util.LinkedList;
import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
public enum WorldScanner implements IWorldScanner { public enum WorldScanner implements IWorldScanner {
@@ -42,7 +39,7 @@ public enum WorldScanner implements IWorldScanner {
if (blocks.contains(null)) { if (blocks.contains(null)) {
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString()); throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString());
} }
ArrayList<BlockPos> res = new ArrayList<>(); LinkedList<BlockPos> res = new LinkedList<>();
if (blocks.isEmpty()) { if (blocks.isEmpty()) {
return res; return res;
} }
@@ -72,7 +69,33 @@ public enum WorldScanner implements IWorldScanner {
continue; continue;
} }
allUnloaded = false; allUnloaded = false;
scanChunkInto(chunkX << 4, chunkZ << 4, chunk, blocks, res, max, yLevelThreshold, playerY); ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
chunkX = chunkX << 4;
chunkZ = chunkZ << 4;
for (int y0 = 0; y0 < 16; y0++) {
ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
if (extendedblockstorage == null) {
continue;
}
int yReal = y0 << 4;
BlockStateContainer bsc = extendedblockstorage.getData();
// the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x;
// for better cache locality, iterate in that order
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
IBlockState state = bsc.get(x, y, z);
if (blocks.contains(state.getBlock())) {
int yy = yReal | y;
res.add(new BlockPos(chunkX | x, yy, chunkZ | z));
if (Math.abs(yy - playerY) < yLevelThreshold) {
foundWithinY = true;
}
}
}
}
}
}
} }
} }
if ((allUnloaded && foundChunks) if ((allUnloaded && foundChunks)
@@ -84,51 +107,4 @@ public enum WorldScanner implements IWorldScanner {
searchRadiusSq++; searchRadiusSq++;
} }
} }
@Override
public List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold) {
if (blocks.isEmpty()) {
return Collections.emptyList();
}
ChunkProviderClient chunkProvider = (ChunkProviderClient) ctx.world().getChunkProvider();
Chunk chunk = chunkProvider.getLoadedChunk(pos.x, pos.z);
int playerY = ctx.playerFeet().getY();
if (chunk == null || chunk.isEmpty()) {
return Collections.emptyList();
}
ArrayList<BlockPos> res = new ArrayList<>();
scanChunkInto(pos.x << 4, pos.z << 4, chunk, blocks, res, max, yLevelThreshold, playerY);
return res;
}
public void scanChunkInto(int chunkX, int chunkZ, Chunk chunk, List<Block> search, Collection<BlockPos> result, int max, int yLevelThreshold, int playerY) {
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
for (int y0 = 0; y0 < 16; y0++) {
ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
if (extendedblockstorage == null) {
continue;
}
int yReal = y0 << 4;
BlockStateContainer bsc = extendedblockstorage.getData();
// the mapping of BlockStateContainer.getIndex from xyz to index is y << 8 | z << 4 | x;
// for better cache locality, iterate in that order
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
IBlockState state = bsc.get(x, y, z);
if (search.contains(state.getBlock())) {
int yy = yReal | y;
result.add(new BlockPos(chunkX | x, yy, chunkZ | z));
if (result.size() >= max && Math.abs(yy - playerY) < yLevelThreshold) {
return;
}
}
}
}
}
}
}
} }
@@ -54,6 +54,11 @@ public final class GameEventHandler implements IEventBus, Helper {
listeners.forEach(l -> l.onPlayerUpdate(event)); listeners.forEach(l -> l.onPlayerUpdate(event));
} }
@Override
public final void onProcessKeyBinds() {
listeners.forEach(IGameEventListener::onProcessKeyBinds);
}
@Override @Override
public final void onSendChatMessage(ChatEvent event) { public final void onSendChatMessage(ChatEvent event) {
listeners.forEach(l -> l.onSendChatMessage(event)); listeners.forEach(l -> l.onSendChatMessage(event));
@@ -121,11 +126,6 @@ public final class GameEventHandler implements IEventBus, Helper {
listeners.forEach(l -> l.onPlayerRotationMove(event)); listeners.forEach(l -> l.onPlayerRotationMove(event));
} }
@Override
public void onPlayerSprintState(SprintStateEvent event) {
listeners.forEach(l -> l.onPlayerSprintState(event));
}
@Override @Override
public void onBlockInteract(BlockInteractEvent event) { public void onBlockInteract(BlockInteractEvent event) {
listeners.forEach(l -> l.onBlockInteract(event)); listeners.forEach(l -> l.onBlockInteract(event));
@@ -25,10 +25,11 @@ import baritone.api.utils.BetterBlockPos;
import baritone.pathing.calc.openset.BinaryHeapOpenSet; import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Moves; import baritone.pathing.movement.Moves;
import baritone.utils.Helper;
import baritone.utils.pathing.BetterWorldBorder; import baritone.utils.pathing.BetterWorldBorder;
import baritone.utils.pathing.Favoring;
import baritone.utils.pathing.MutableMoveResult; import baritone.utils.pathing.MutableMoveResult;
import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
/** /**
@@ -36,14 +37,14 @@ import java.util.Optional;
* *
* @author leijurv * @author leijurv
*/ */
public final class AStarPathFinder extends AbstractNodeCostSearch { public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
private final Favoring favoring; private final HashSet<Long> favoredPositions;
private final CalculationContext calcContext; private final CalculationContext calcContext;
public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) { public AStarPathFinder(int startX, int startY, int startZ, Goal goal, HashSet<Long> favoredPositions, CalculationContext context) {
super(startX, startY, startZ, goal, context); super(startX, startY, startZ, goal, context);
this.favoring = favoring; this.favoredPositions = favoredPositions;
this.calcContext = context; this.calcContext = context;
} }
@@ -54,14 +55,17 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
startNode.combinedCost = startNode.estimatedCostToGoal; startNode.combinedCost = startNode.estimatedCostToGoal;
BinaryHeapOpenSet openSet = new BinaryHeapOpenSet(); BinaryHeapOpenSet openSet = new BinaryHeapOpenSet();
openSet.insert(startNode); openSet.insert(startNode);
double[] bestHeuristicSoFar = new double[COEFFICIENTS.length];//keep track of the best node by the metric of (estimatedCostToGoal + cost / COEFFICIENTS[i]) startNode.isOpen = true;
bestSoFar = new PathNode[COEFFICIENTS.length];//keep track of the best node by the metric of (estimatedCostToGoal + cost / COEFFICIENTS[i])
double[] bestHeuristicSoFar = new double[COEFFICIENTS.length];
for (int i = 0; i < bestHeuristicSoFar.length; i++) { for (int i = 0; i < bestHeuristicSoFar.length; i++) {
bestHeuristicSoFar[i] = startNode.estimatedCostToGoal; bestHeuristicSoFar[i] = startNode.estimatedCostToGoal;
bestSoFar[i] = startNode; bestSoFar[i] = startNode;
} }
MutableMoveResult res = new MutableMoveResult(); MutableMoveResult res = new MutableMoveResult();
BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world.getWorldBorder()); HashSet<Long> favored = favoredPositions;
long startTime = System.currentTimeMillis(); BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world().getWorldBorder());
long startTime = System.nanoTime() / 1000000L;
boolean slowPath = Baritone.settings().slowPath.get(); boolean slowPath = Baritone.settings().slowPath.get();
if (slowPath) { if (slowPath) {
logDebug("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.<Long>get() + "ms instead of " + primaryTimeout + "ms"); logDebug("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.<Long>get() + "ms instead of " + primaryTimeout + "ms");
@@ -72,16 +76,14 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
int numNodes = 0; int numNodes = 0;
int numMovementsConsidered = 0; int numMovementsConsidered = 0;
int numEmptyChunk = 0; int numEmptyChunk = 0;
boolean isFavoring = !favoring.isEmpty(); boolean favoring = favored != null;
int timeCheckInterval = 1 << 6;
int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior
double minimumImprovement = Baritone.settings().minimumImprovementRepropagation.get() ? MIN_IMPROVEMENT : 0; double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get();
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && !cancelRequested) { while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && !cancelRequested) {
if ((numNodes & (timeCheckInterval - 1)) == 0) { // only call this once every 64 nodes (about half a millisecond) long now = System.nanoTime() / 1000000L;
long now = System.currentTimeMillis(); // since nanoTime is slow on windows (takes many microseconds) if (now - failureTimeoutTime >= 0 || (!failing && now - primaryTimeoutTime >= 0)) {
if (now - failureTimeoutTime >= 0 || (!failing && now - primaryTimeoutTime >= 0)) { break;
break;
}
} }
if (slowPath) { if (slowPath) {
try { try {
@@ -90,10 +92,11 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
} }
} }
PathNode currentNode = openSet.removeLowest(); PathNode currentNode = openSet.removeLowest();
currentNode.isOpen = false;
mostRecentConsidered = currentNode; mostRecentConsidered = currentNode;
numNodes++; numNodes++;
if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) { if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) {
logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, " + numMovementsConsidered + " movements considered"); logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext)); return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext));
} }
for (Moves moves : Moves.values()) { for (Moves moves : Moves.values()) {
@@ -119,13 +122,13 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
if (actionCost >= ActionCosts.COST_INF) { if (actionCost >= ActionCosts.COST_INF) {
continue; continue;
} }
if (actionCost <= 0 || Double.isNaN(actionCost)) { if (actionCost <= 0) {
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost); throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
} }
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218 if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
continue; continue;
} }
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) { if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) {
throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ); throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
} }
@@ -133,24 +136,39 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset)); throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset));
} }
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z); long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
if (isFavoring) { if (favoring && favored.contains(hashCode)) {
// see issue #18 // see issue #18
actionCost *= favoring.calculate(hashCode); actionCost *= favorCoeff;
} }
PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode); PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode);
double tentativeCost = currentNode.cost + actionCost; double tentativeCost = currentNode.cost + actionCost;
if (neighbor.cost - tentativeCost > minimumImprovement) { if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) {
throw new IllegalStateException(moves + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost);
}
double improvementBy = neighbor.cost - tentativeCost;
// there are floating point errors caused by random combinations of traverse and diagonal over a flat area
// that means that sometimes there's a cost improvement of like 10 ^ -16
// it's not worth the time to update the costs, decrease-key the heap, potentially repropagate, etc
if (improvementBy < 0.01 && minimumImprovementRepropagation) {
// who cares about a hundredth of a tick? that's half a millisecond for crying out loud!
continue;
}
neighbor.previous = currentNode; neighbor.previous = currentNode;
neighbor.cost = tentativeCost; neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal; neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen()) { if (neighbor.isOpen) {
openSet.update(neighbor); openSet.update(neighbor);
} else { } else {
neighbor.isOpen = true;
openSet.insert(neighbor);//dont double count, dont insert into open set if it's already there openSet.insert(neighbor);//dont double count, dont insert into open set if it's already there
} }
for (int i = 0; i < COEFFICIENTS.length; i++) { for (int i = 0; i < bestSoFar.length; i++) {
double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i]; double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i];
if (bestHeuristicSoFar[i] - heuristic > minimumImprovement) { if (heuristic < bestHeuristicSoFar[i]) {
if (bestHeuristicSoFar[i] - heuristic < 0.01 && minimumImprovementRepropagation) {
continue;
}
bestHeuristicSoFar[i] = heuristic; bestHeuristicSoFar[i] = heuristic;
bestSoFar[i] = neighbor; bestSoFar[i] = neighbor;
if (getDistFromStartSq(neighbor) > MIN_DIST_PATH * MIN_DIST_PATH) { if (getDistFromStartSq(neighbor) > MIN_DIST_PATH * MIN_DIST_PATH) {
@@ -167,11 +185,29 @@ public final class AStarPathFinder extends AbstractNodeCostSearch {
System.out.println(numMovementsConsidered + " movements considered"); System.out.println(numMovementsConsidered + " movements considered");
System.out.println("Open set size: " + openSet.size()); System.out.println("Open set size: " + openSet.size());
System.out.println("PathNode map size: " + mapSize()); System.out.println("PathNode map size: " + mapSize());
System.out.println((int) (numNodes * 1.0 / ((System.currentTimeMillis() - startTime) / 1000F)) + " nodes per second"); System.out.println((int) (numNodes * 1.0 / ((System.nanoTime() / 1000000L - startTime) / 1000F)) + " nodes per second");
Optional<IPath> result = bestSoFar(true, numNodes); double bestDist = 0;
if (result.isPresent()) { for (int i = 0; i < bestSoFar.length; i++) {
logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, " + numMovementsConsidered + " movements considered"); if (bestSoFar[i] == null) {
continue;
}
double dist = getDistFromStartSq(bestSoFar[i]);
if (dist > bestDist) {
bestDist = dist;
}
if (dist > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, A* cost coefficient " + COEFFICIENTS[i] + ", " + numMovementsConsidered + " movements considered");
if (COEFFICIENTS[i] >= 3) {
System.out.println("Warning: cost coefficient is greater than three! Probably means that");
System.out.println("the path I found is pretty terrible (like sneak-bridging for dozens of blocks)");
System.out.println("But I'm going to do it anyway, because yolo");
}
System.out.println("Path goes for " + Math.sqrt(dist) + " blocks");
return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal, calcContext));
}
} }
return result; logDebug("Even with a cost coefficient of " + COEFFICIENTS[COEFFICIENTS.length - 1] + ", I couldn't get more than " + Math.sqrt(bestDist) + " blocks");
logDebug("No path found =(");
return Optional.empty();
} }
} }
@@ -21,7 +21,6 @@ import baritone.Baritone;
import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.PathCalculationResult; import baritone.api.utils.PathCalculationResult;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.utils.Helper; import baritone.utils.Helper;
@@ -34,7 +33,7 @@ import java.util.Optional;
* *
* @author leijurv * @author leijurv
*/ */
public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { public abstract class AbstractNodeCostSearch implements IPathFinder {
protected final int startX; protected final int startX;
protected final int startY; protected final int startY;
@@ -53,7 +52,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
protected PathNode mostRecentConsidered; protected PathNode mostRecentConsidered;
protected final PathNode[] bestSoFar = new PathNode[COEFFICIENTS.length]; protected PathNode[] bestSoFar;
private volatile boolean isFinished; private volatile boolean isFinished;
@@ -63,23 +62,13 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
* This is really complicated and hard to explain. I wrote a comment in the old version of MineBot but it was so * This is really complicated and hard to explain. I wrote a comment in the old version of MineBot but it was so
* long it was easier as a Google Doc (because I could insert charts). * long it was easier as a Google Doc (because I could insert charts).
* *
* @see <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit">here</a> * @see <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit"></a>
*/ */
protected static final double[] COEFFICIENTS = {1.5, 2, 2.5, 3, 4, 5, 10}; protected static final double[] COEFFICIENTS = {1.5, 2, 2.5, 3, 4, 5, 10}; // big TODO tune
/** /**
* If a path goes less than 5 blocks and doesn't make it to its goal, it's not worth considering. * If a path goes less than 5 blocks and doesn't make it to its goal, it's not worth considering.
*/ */
protected static final double MIN_DIST_PATH = 5; protected final static double MIN_DIST_PATH = 5;
/**
* there are floating point errors caused by random combinations of traverse and diagonal over a flat area
* that means that sometimes there's a cost improvement of like 10 ^ -16
* it's not worth the time to update the costs, decrease-key the heap, potentially repropagate, etc
* <p>
* who cares about a hundredth of a tick? that's half a millisecond for crying out loud!
*/
protected static final double MIN_IMPROVEMENT = 0.01;
AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal, CalculationContext context) { AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal, CalculationContext context) {
this.startX = startX; this.startX = startX;
@@ -97,30 +86,18 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
@Override @Override
public synchronized PathCalculationResult calculate(long primaryTimeout, long failureTimeout) { public synchronized PathCalculationResult calculate(long primaryTimeout, long failureTimeout) {
if (isFinished) { if (isFinished) {
throw new IllegalStateException("Path finder cannot be reused!"); throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!");
} }
cancelRequested = false; cancelRequested = false;
try { try {
IPath path = calculate0(primaryTimeout, failureTimeout).map(IPath::postProcess).orElse(null); IPath path = calculate0(primaryTimeout, failureTimeout).map(IPath::postProcess).orElse(null);
isFinished = true;
if (cancelRequested) { if (cancelRequested) {
return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION); return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, path);
} }
if (path == null) { if (path == null) {
return new PathCalculationResult(PathCalculationResult.Type.FAILURE); return new PathCalculationResult(PathCalculationResult.Type.FAILURE);
} }
int previousLength = path.length();
path = path.cutoffAtLoadedChunks(context.bsi);
if (path.length() < previousLength) {
Helper.HELPER.logDebug("Cutting off path at edge of loaded chunks");
Helper.HELPER.logDebug("Length decreased by " + (previousLength - path.length()));
} else {
Helper.HELPER.logDebug("Path ends within loaded chunks");
}
previousLength = path.length();
path = path.staticCutoff(goal);
if (path.length() < previousLength) {
Helper.HELPER.logDebug("Static cutoff " + previousLength + " to " + path.length());
}
if (goal.isInGoal(path.getDest())) { if (goal.isInGoal(path.getDest())) {
return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_TO_GOAL, path); return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_TO_GOAL, path);
} else { } else {
@@ -158,14 +135,9 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
* for the node mapped to the specified pos. If no node is found, * for the node mapped to the specified pos. If no node is found,
* a new node is created. * a new node is created.
* *
* @param x The x position of the node
* @param y The y position of the node
* @param z The z position of the node
* @param hashCode The hash code of the node, provided by {@link BetterBlockPos#longHash(int, int, int)}
* @return The associated node * @return The associated node
* @see <a href="https://github.com/cabaletta/baritone/issues/107">Issue #107</a> * @see <a href="https://github.com/cabaletta/baritone/issues/107">Issue #107</a>
*/ */
protected PathNode getNodeAtPosition(int x, int y, int z, long hashCode) { protected PathNode getNodeAtPosition(int x, int y, int z, long hashCode) {
PathNode node = map.get(hashCode); PathNode node = map.get(hashCode);
if (node == null) { if (node == null) {
@@ -180,43 +152,25 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal, context)); return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal, context));
} }
@Override protected int mapSize() {
public Optional<IPath> bestPathSoFar() { return map.size();
return bestSoFar(false, 0);
} }
protected Optional<IPath> bestSoFar(boolean logInfo, int numNodes) { @Override
public Optional<IPath> bestPathSoFar() {
if (startNode == null || bestSoFar == null) { if (startNode == null || bestSoFar == null) {
return Optional.empty(); return Optional.empty();
} }
double bestDist = 0; for (int i = 0; i < bestSoFar.length; i++) {
for (int i = 0; i < COEFFICIENTS.length; i++) {
if (bestSoFar[i] == null) { if (bestSoFar[i] == null) {
continue; continue;
} }
double dist = getDistFromStartSq(bestSoFar[i]); if (getDistFromStartSq(bestSoFar[i]) > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared
if (dist > bestDist) { return Optional.of(new Path(startNode, bestSoFar[i], 0, goal, context));
bestDist = dist;
}
if (dist > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared
if (logInfo) {
if (COEFFICIENTS[i] >= 3) {
System.out.println("Warning: cost coefficient is greater than three! Probably means that");
System.out.println("the path I found is pretty terrible (like sneak-bridging for dozens of blocks)");
System.out.println("But I'm going to do it anyway, because yolo");
}
System.out.println("Path goes for " + Math.sqrt(dist) + " blocks");
logDebug("A* cost coefficient " + COEFFICIENTS[i]);
}
return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal, context));
} }
} }
// instead of returning bestSoFar[0], be less misleading // instead of returning bestSoFar[0], be less misleading
// if it actually won't find any path, don't make them think it will by rendering a dark blue that will never actually happen // if it actually won't find any path, don't make them think it will by rendering a dark blue that will never actually happen
if (logInfo) {
logDebug("Even with a cost coefficient of " + COEFFICIENTS[COEFFICIENTS.length - 1] + ", I couldn't get more than " + Math.sqrt(bestDist) + " blocks");
logDebug("No path found =(");
}
return Optional.empty(); return Optional.empty();
} }
@@ -229,12 +183,4 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper {
public final Goal getGoal() { public final Goal getGoal() {
return goal; return goal;
} }
public BetterBlockPos getStart() {
return new BetterBlockPos(startX, startY, startZ);
}
protected int mapSize() {
return map.size();
}
} }
@@ -132,9 +132,7 @@ class Path extends PathBase {
Movement move = moves.apply0(context, src); Movement move = moves.apply0(context, src);
if (move.getDest().equals(dest)) { if (move.getDest().equals(dest)) {
// have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution
// however, taking into account possible favoring that could skew the node cost, we really want the stricter limit of the two move.override(cost);
// so we take the minimum of the path node cost difference, and the calculated cost
move.override(Math.min(move.calculateCost(context), cost));
return move; return move;
} }
} }
@@ -58,6 +58,12 @@ public final class PathNode {
*/ */
public PathNode previous; public PathNode previous;
/**
* Is this a member of the open set in A*? (only used during pathfinding)
* Instead of doing a costly member check in the open set, cache membership in each node individually too.
*/
public boolean isOpen;
/** /**
* Where is this node in the array flattenization of the binary heap? Needed for decrease-key operations. * Where is this node in the array flattenization of the binary heap? Needed for decrease-key operations.
*/ */
@@ -67,19 +73,12 @@ public final class PathNode {
this.previous = null; this.previous = null;
this.cost = ActionCosts.COST_INF; this.cost = ActionCosts.COST_INF;
this.estimatedCostToGoal = goal.heuristic(x, y, z); this.estimatedCostToGoal = goal.heuristic(x, y, z);
if (Double.isNaN(estimatedCostToGoal)) { this.isOpen = false;
throw new IllegalStateException(goal + " calculated implausible heuristic");
}
this.heapPosition = -1;
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
} }
public boolean isOpen() {
return heapPosition != -1;
}
/** /**
* TODO: Possibly reimplement hashCode and equals. They are necessary for this class to function but they could be done better * TODO: Possibly reimplement hashCode and equals. They are necessary for this class to function but they could be done better
* *
@@ -59,7 +59,7 @@ public final class BinaryHeapOpenSet implements IOpenSet {
@Override @Override
public final void insert(PathNode value) { public final void insert(PathNode value) {
if (size >= array.length - 1) { if (size >= array.length - 1) {
array = Arrays.copyOf(array, array.length << 1); array = Arrays.copyOf(array, array.length * 2);
} }
size++; size++;
value.heapPosition = size; value.heapPosition = size;
@@ -72,7 +72,6 @@ public final class BinaryHeapOpenSet implements IOpenSet {
int index = val.heapPosition; int index = val.heapPosition;
int parentInd = index >>> 1; int parentInd = index >>> 1;
double cost = val.combinedCost; double cost = val.combinedCost;
PathNode[] array = this.array;
PathNode parentNode = array[parentInd]; PathNode parentNode = array[parentInd];
while (index > 1 && parentNode.combinedCost > cost) { while (index > 1 && parentNode.combinedCost > cost) {
array[index] = parentNode; array[index] = parentNode;
@@ -95,50 +94,40 @@ public final class BinaryHeapOpenSet implements IOpenSet {
if (size == 0) { if (size == 0) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
PathNode[] array = this.array;
PathNode result = array[1]; PathNode result = array[1];
PathNode val = array[size]; PathNode val = array[size];
array[1] = val; array[1] = val;
val.heapPosition = 1; val.heapPosition = 1;
array[size] = null; array[size] = null;
int size = --this.size; size--;
result.heapPosition = -1; result.heapPosition = -1;
if (size < 2) { if (size < 2) {
return result; return result;
} }
int index = 1; int index = 1;
int smallerChild = 1; int smallerChild = 2;
double cost = val.combinedCost; double cost = val.combinedCost;
while ((smallerChild <<= 1) < size) { do {
PathNode smallerChildNode = array[smallerChild]; PathNode smallerChildNode = array[smallerChild];
PathNode otherChildNode = array[smallerChild + 1];
double smallerChildCost = smallerChildNode.combinedCost; double smallerChildCost = smallerChildNode.combinedCost;
double rightChildCost = otherChildNode.combinedCost; if (smallerChild < size) {
if (smallerChildCost > rightChildCost) { PathNode rightChildNode = array[smallerChild + 1];
smallerChild++; double rightChildCost = rightChildNode.combinedCost;
smallerChildCost = rightChildCost; if (smallerChildCost > rightChildCost) {
smallerChildNode = otherChildNode; smallerChild++;
smallerChildCost = rightChildCost;
smallerChildNode = rightChildNode;
}
} }
if (cost <= smallerChildCost) { if (cost <= smallerChildCost) {
return result; break;
} }
array[index] = smallerChildNode; array[index] = smallerChildNode;
array[smallerChild] = val; array[smallerChild] = val;
val.heapPosition = smallerChild; val.heapPosition = smallerChild;
smallerChildNode.heapPosition = index; smallerChildNode.heapPosition = index;
index = smallerChild; index = smallerChild;
} } while ((smallerChild <<= 1) <= size);
// if we get here, then smallerChild >= size
// one last swap to check
if (smallerChild == size) {
PathNode onlyChildNode = array[smallerChild];
if (cost > onlyChildNode.combinedCost) {
array[index] = onlyChildNode;
array[smallerChild] = val;
val.heapPosition = smallerChild;
onlyChildNode.heapPosition = index;
}
}
return result; return result;
} }
} }
@@ -42,50 +42,36 @@ public class CalculationContext {
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET); private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
public final IBaritone baritone; private final IBaritone baritone;
public final World world; private final EntityPlayerSP player;
public final WorldData worldData; private final World world;
public final BlockStateInterface bsi; private final WorldData worldData;
public final ToolSet toolSet; private final BlockStateInterface bsi;
public final boolean hasWaterBucket; private final ToolSet toolSet;
public final boolean hasThrowaway; private final boolean hasWaterBucket;
public final boolean canSprint; private final boolean hasThrowaway;
public final double placeBlockCost; private final boolean canSprint;
public final boolean allowBreak; private final double placeBlockCost;
public final boolean allowParkour; private final boolean allowBreak;
public final boolean allowParkourPlace; private final int maxFallHeightNoWater;
public final boolean allowJumpAt256; private final int maxFallHeightBucket;
public final boolean assumeWalkOnWater; private final double waterWalkSpeed;
public final boolean allowDiagonalDescend; private final double breakBlockAdditionalCost;
public final int maxFallHeightNoWater; private final BetterWorldBorder worldBorder;
public final int maxFallHeightBucket;
public final double waterWalkSpeed;
public final double breakBlockAdditionalCost;
public final double jumpPenalty;
public final double walkOnWaterOnePenalty;
public final BetterWorldBorder worldBorder;
public CalculationContext(IBaritone baritone) { public CalculationContext(IBaritone baritone) {
this(baritone, false);
}
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
this.baritone = baritone; this.baritone = baritone;
EntityPlayerSP player = baritone.getPlayerContext().player(); this.player = baritone.getPlayerContext().player();
this.world = baritone.getPlayerContext().world(); this.world = baritone.getPlayerContext().world();
this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld(); this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld();
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread); // TODO TODO TODO this.bsi = new BlockStateInterface(world, worldData); // TODO TODO TODO
// new CalculationContext() needs to happen, can't add an argument (i'll beat you), can we get the world provider from currentlyTicking?
this.toolSet = new ToolSet(player); this.toolSet = new ToolSet(player);
this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(baritone.getPlayerContext(), false); this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(baritone.getPlayerContext(), false);
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether(); this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether();
this.canSprint = Baritone.settings().allowSprint.get() && player.getFoodStats().getFoodLevel() > 6; this.canSprint = Baritone.settings().allowSprint.get() && player.getFoodStats().getFoodLevel() > 6;
this.placeBlockCost = Baritone.settings().blockPlacementPenalty.get(); this.placeBlockCost = Baritone.settings().blockPlacementPenalty.get();
this.allowBreak = Baritone.settings().allowBreak.get(); this.allowBreak = Baritone.settings().allowBreak.get();
this.allowParkour = Baritone.settings().allowParkour.get();
this.allowParkourPlace = Baritone.settings().allowParkourPlace.get();
this.allowJumpAt256 = Baritone.settings().allowJumpAt256.get();
this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.get();
this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.get();
this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.get(); this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.get();
this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.get(); this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.get();
int depth = EnchantmentHelper.getDepthStriderModifier(player); int depth = EnchantmentHelper.getDepthStriderModifier(player);
@@ -95,8 +81,6 @@ public class CalculationContext {
float mult = depth / 3.0F; float mult = depth / 3.0F;
this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult; this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult;
this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.get(); this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.get();
this.jumpPenalty = Baritone.settings().jumpPenalty.get();
this.walkOnWaterOnePenalty = Baritone.settings().walkOnWaterOnePenalty.get();
// why cache these things here, why not let the movements just get directly from settings? // why cache these things here, why not let the movements just get directly from settings?
// because if some movements are calculated one way and others are calculated another way, // because if some movements are calculated one way and others are calculated another way,
// then you get a wildly inconsistent path that isn't optimal for either scenario. // then you get a wildly inconsistent path that isn't optimal for either scenario.
@@ -124,7 +108,7 @@ public class CalculationContext {
} }
public boolean canPlaceThrowawayAt(int x, int y, int z) { public boolean canPlaceThrowawayAt(int x, int y, int z) {
if (!hasThrowaway) { // only true if allowPlace is true, see constructor if (!hasThrowaway()) { // only true if allowPlace is true, see constructor
return false; return false;
} }
if (isPossiblyProtected(x, y, z)) { if (isPossiblyProtected(x, y, z)) {
@@ -134,7 +118,7 @@ public class CalculationContext {
} }
public boolean canBreakAt(int x, int y, int z) { public boolean canBreakAt(int x, int y, int z) {
if (!allowBreak) { if (!allowBreak()) {
return false; return false;
} }
return !isPossiblyProtected(x, y, z); return !isPossiblyProtected(x, y, z);
@@ -144,4 +128,60 @@ public class CalculationContext {
// TODO more protection logic here; see #220 // TODO more protection logic here; see #220
return false; return false;
} }
public World world() {
return world;
}
public EntityPlayerSP player() {
return player;
}
public BlockStateInterface bsi() {
return bsi;
}
public WorldData worldData() {
return worldData;
}
public ToolSet getToolSet() {
return toolSet;
}
public boolean hasWaterBucket() {
return hasWaterBucket;
}
public boolean hasThrowaway() {
return hasThrowaway;
}
public boolean canSprint() {
return canSprint;
}
public double placeBlockCost() {
return placeBlockCost;
}
public boolean allowBreak() {
return allowBreak;
}
public int maxFallHeightNoWater() {
return maxFallHeightNoWater;
}
public int maxFallHeightBucket() {
return maxFallHeightBucket;
}
public double waterWalkSpeed() {
return waterWalkSpeed;
}
public double breakBlockAdditionalCost() {
return breakBlockAdditionalCost;
}
} }
@@ -26,6 +26,7 @@ import baritone.utils.BlockStateInterface;
import net.minecraft.block.BlockLiquid; import net.minecraft.block.BlockLiquid;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -34,7 +35,7 @@ import java.util.Optional;
public abstract class Movement implements IMovement, MovementHelper { public abstract class Movement implements IMovement, MovementHelper {
protected static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN}; protected static final EnumFacing[] HORIZONTALS = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST};
protected final IBaritone baritone; protected final IBaritone baritone;
protected final IPlayerContext ctx; protected final IPlayerContext ctx;
@@ -84,7 +85,7 @@ public abstract class Movement implements IMovement, MovementHelper {
return cost; return cost;
} }
public abstract double calculateCost(CalculationContext context); protected abstract double calculateCost(CalculationContext context);
@Override @Override
public double recalculateCost() { public double recalculateCost() {
@@ -123,11 +124,14 @@ public abstract class Movement implements IMovement, MovementHelper {
baritone.getLookBehavior().updateTarget( baritone.getLookBehavior().updateTarget(
rotation, rotation,
currentState.getTarget().hasToForceRotations())); currentState.getTarget().hasToForceRotations()));
baritone.getInputOverrideHandler().clearAllKeys();
// TODO: calculate movement inputs from latestState.getGoal().position
// latestState.getTarget().position.ifPresent(null); NULL CONSUMER REALLY SHOULDN'T BE THE FINAL THING YOU SHOULD REALLY REPLACE THIS WITH ALMOST ACTUALLY ANYTHING ELSE JUST PLEASE DON'T LEAVE IT AS IT IS THANK YOU KANYE
currentState.getInputStates().forEach((input, forced) -> { currentState.getInputStates().forEach((input, forced) -> {
baritone.getInputOverrideHandler().setInputForceState(input, forced); baritone.getInputOverrideHandler().setInputForceState(input, forced);
}); });
currentState.getInputStates().clear(); currentState.getInputStates().replaceAll((input, forced) -> false);
// If the current status indicates a completed movement // If the current status indicates a completed movement
if (currentState.getStatus().isComplete()) { if (currentState.getStatus().isComplete()) {
@@ -147,10 +151,9 @@ public abstract class Movement implements IMovement, MovementHelper {
somethingInTheWay = true; somethingInTheWay = true;
Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), blockPos, ctx.playerController().getBlockReachDistance()); Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), blockPos, ctx.playerController().getBlockReachDistance());
if (reachable.isPresent()) { if (reachable.isPresent()) {
Rotation rotTowardsBlock = reachable.get();
MovementHelper.switchToBestToolFor(ctx, BlockStateInterface.get(ctx, blockPos)); MovementHelper.switchToBestToolFor(ctx, BlockStateInterface.get(ctx, blockPos));
state.setTarget(new MovementState.MovementTarget(rotTowardsBlock, true)); state.setTarget(new MovementState.MovementTarget(reachable.get(), true));
if (Objects.equals(ctx.getSelectedBlock().orElse(null), blockPos) || ctx.playerRotations().isReallyCloseTo(rotTowardsBlock)) { if (Objects.equals(ctx.getSelectedBlock().orElse(null), blockPos)) {
state.setInput(Input.CLICK_LEFT, true); state.setInput(Input.CLICK_LEFT, true);
} }
return false; return false;
@@ -201,10 +204,10 @@ public abstract class Movement implements IMovement, MovementHelper {
} }
/** /**
* Calculate latest movement state. Gets called once a tick. * Calculate latest movement state.
* Gets called once a tick.
* *
* @param state The current state * @return
* @return The new state
*/ */
public MovementState updateState(MovementState state) { public MovementState updateState(MovementState state) {
if (!prepared(state)) { if (!prepared(state)) {
@@ -226,7 +229,7 @@ public abstract class Movement implements IMovement, MovementHelper {
} }
public void checkLoadedChunk(CalculationContext context) { public void checkLoadedChunk(CalculationContext context) {
calculatedWhileLoaded = context.bsi.worldContainsLoadedChunk(dest.x, dest.z); calculatedWhileLoaded = !(context.world().getChunk(getDest()) instanceof EmptyChunk);
} }
@Override @Override
@@ -241,13 +244,14 @@ public abstract class Movement implements IMovement, MovementHelper {
toWalkIntoCached = null; toWalkIntoCached = null;
} }
public List<BlockPos> toBreak(BlockStateInterface bsi) { @Override
public List<BlockPos> toBreak() {
if (toBreakCached != null) { if (toBreakCached != null) {
return toBreakCached; return toBreakCached;
} }
List<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (BetterBlockPos positionToBreak : positionsToBreak) { for (BetterBlockPos positionToBreak : positionsToBreak) {
if (!MovementHelper.canWalkThrough(bsi, positionToBreak.x, positionToBreak.y, positionToBreak.z)) { if (!MovementHelper.canWalkThrough(ctx, positionToBreak)) {
result.add(positionToBreak); result.add(positionToBreak);
} }
} }
@@ -255,19 +259,21 @@ public abstract class Movement implements IMovement, MovementHelper {
return result; return result;
} }
public List<BlockPos> toPlace(BlockStateInterface bsi) { @Override
public List<BlockPos> toPlace() {
if (toPlaceCached != null) { if (toPlaceCached != null) {
return toPlaceCached; return toPlaceCached;
} }
List<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
if (positionToPlace != null && !MovementHelper.canWalkOn(bsi, positionToPlace.x, positionToPlace.y, positionToPlace.z)) { if (positionToPlace != null && !MovementHelper.canWalkOn(ctx, positionToPlace)) {
result.add(positionToPlace); result.add(positionToPlace);
} }
toPlaceCached = result; toPlaceCached = result;
return result; return result;
} }
public List<BlockPos> toWalkInto(BlockStateInterface bsi) { // overridden by movementdiagonal @Override
public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
if (toWalkIntoCached == null) { if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>(); toWalkIntoCached = new ArrayList<>();
} }
@@ -18,9 +18,7 @@
package baritone.pathing.movement; package baritone.pathing.movement;
import baritone.Baritone; import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.pathing.movement.ActionCosts; import baritone.api.pathing.movement.ActionCosts;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*; import baritone.api.utils.*;
import baritone.api.utils.input.Input; import baritone.api.utils.input.Input;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
@@ -37,10 +35,8 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World;
import net.minecraft.util.math.Vec3d; import net.minecraft.world.chunk.EmptyChunk;
import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP;
/** /**
* Static helpers for cost calculation * Static helpers for cost calculation
@@ -74,7 +70,7 @@ public interface MovementHelper extends ActionCosts, Helper {
if (block == Blocks.AIR) { // early return for most common case if (block == Blocks.AIR) { // early return for most common case
return true; return true;
} }
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL || block == Blocks.COCOA) { if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL) {
return false; return false;
} }
if (block instanceof BlockDoor || block instanceof BlockFenceGate) { if (block instanceof BlockDoor || block instanceof BlockFenceGate) {
@@ -96,11 +92,7 @@ public interface MovementHelper extends ActionCosts, Helper {
if (snow) { if (snow) {
// the check in BlockSnow.isPassable is layers < 5 // the check in BlockSnow.isPassable is layers < 5
// while actually, we want < 3 because 3 or greater makes it impassable in a 2 high ceiling // while actually, we want < 3 because 3 or greater makes it impassable in a 2 high ceiling
if (state.getValue(BlockSnow.LAYERS) >= 3) { return state.getValue(BlockSnow.LAYERS) < 3;
return false;
}
// ok, it's low enough we could walk through it, but is it supported?
return canWalkOn(bsi, x, y - 1, z);
} }
if (trapdoor) { if (trapdoor) {
return !state.getValue(BlockTrapDoor.OPEN); // see BlockTrapDoor.isPassable return !state.getValue(BlockTrapDoor.OPEN); // see BlockTrapDoor.isPassable
@@ -130,11 +122,7 @@ public interface MovementHelper extends ActionCosts, Helper {
* canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click), * canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click),
* not including water, and not including ladders or vines or cobwebs (they slow us down) * not including water, and not including ladders or vines or cobwebs (they slow us down)
* *
* @param context Calculation context to provide block state lookup * @return
* @param x The block's x position
* @param y The block's y position
* @param z The block's z position
* @return Whether or not the block at the specified position
*/ */
static boolean fullyPassable(CalculationContext context, int x, int y, int z) { static boolean fullyPassable(CalculationContext context, int x, int y, int z) {
return fullyPassable(context.get(x, y, z)); return fullyPassable(context.get(x, y, z));
@@ -151,7 +139,6 @@ public interface MovementHelper extends ActionCosts, Helper {
|| block == Blocks.WEB || block == Blocks.WEB
|| block == Blocks.VINE || block == Blocks.VINE
|| block == Blocks.LADDER || block == Blocks.LADDER
|| block == Blocks.COCOA
|| block instanceof BlockDoor || block instanceof BlockDoor
|| block instanceof BlockFenceGate || block instanceof BlockFenceGate
|| block instanceof BlockSnow || block instanceof BlockSnow
@@ -164,7 +151,7 @@ public interface MovementHelper extends ActionCosts, Helper {
return block.isPassable(null, null); return block.isPassable(null, null);
} }
static boolean isReplacable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) { static boolean isReplacable(int x, int y, int z, IBlockState state, World world) {
// for MovementTraverse and MovementAscend // for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case // block double plant defaults to true when the block doesn't match, so don't need to check that case
// all other overrides just return true or false // all other overrides just return true or false
@@ -176,13 +163,9 @@ public interface MovementHelper extends ActionCosts, Helper {
* } * }
*/ */
Block block = state.getBlock(); Block block = state.getBlock();
if (block == Blocks.AIR || isWater(block)) {
// early return for common cases hehe
return true;
}
if (block instanceof BlockSnow) { if (block instanceof BlockSnow) {
// as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible) // as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
if (!bsi.worldContainsLoadedChunk(x, z)) { if (world.getChunk(x >> 4, z >> 4) instanceof EmptyChunk) {
return true; return true;
} }
return state.getValue(BlockSnow.LAYERS) == 1; return state.getValue(BlockSnow.LAYERS) == 1;
@@ -255,12 +238,7 @@ public interface MovementHelper extends ActionCosts, Helper {
* through? Includes water because we know that we automatically jump on * through? Includes water because we know that we automatically jump on
* water * water
* *
* @param bsi Block state provider * @return
* @param x The block's x position
* @param y The block's y position
* @param z The block's z position
* @param state The state of the block at the specified location
* @return Whether or not the specified block can be walked on
*/ */
static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) { static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock(); Block block = state.getBlock();
@@ -346,24 +324,24 @@ public interface MovementHelper extends ActionCosts, Helper {
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) { static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
Block block = state.getBlock(); Block block = state.getBlock();
if (!canWalkThrough(context.bsi, x, y, z, state)) { if (!canWalkThrough(context.bsi(), x, y, z, state)) {
if (!context.canBreakAt(x, y, z)) { if (!context.canBreakAt(x, y, z)) {
return COST_INF; return COST_INF;
} }
if (avoidBreaking(context.bsi, x, y, z, state)) { if (avoidBreaking(context.bsi(), x, y, z, state)) {
return COST_INF; return COST_INF;
} }
if (block instanceof BlockLiquid) { if (block instanceof BlockLiquid) {
return COST_INF; return COST_INF;
} }
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
double strVsBlock = context.toolSet.getStrVsBlock(state); double strVsBlock = context.getToolSet().getStrVsBlock(state);
if (strVsBlock <= 0) { if (strVsBlock <= 0) {
return COST_INF; return COST_INF;
} }
double result = m / strVsBlock; double result = m / strVsBlock;
result += context.breakBlockAdditionalCost; result += context.breakBlockAdditionalCost();
if (includeFalling) { if (includeFalling) {
IBlockState above = context.get(x, y + 1, z); IBlockState above = context.get(x, y + 1, z);
if (above.getBlock() instanceof BlockFalling) { if (above.getBlock() instanceof BlockFalling) {
@@ -384,8 +362,7 @@ public interface MovementHelper extends ActionCosts, Helper {
/** /**
* AutoTool for a specific block * AutoTool for a specific block
* *
* @param ctx The player context * @param b the blockstate to mine
* @param b the blockstate to mine
*/ */
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b) { static void switchToBestToolFor(IPlayerContext ctx, IBlockState b) {
switchToBestToolFor(ctx, b, new ToolSet(ctx.player())); switchToBestToolFor(ctx, b, new ToolSet(ctx.player()));
@@ -394,9 +371,8 @@ public interface MovementHelper extends ActionCosts, Helper {
/** /**
* AutoTool for a specific block with precomputed ToolSet data * AutoTool for a specific block with precomputed ToolSet data
* *
* @param ctx The player context * @param b the blockstate to mine
* @param b the blockstate to mine * @param ts previously calculated ToolSet
* @param ts previously calculated ToolSet
*/ */
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b, ToolSet ts) { static void switchToBestToolFor(IPlayerContext ctx, IBlockState b, ToolSet ts) {
ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock()); ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock());
@@ -489,50 +465,7 @@ public interface MovementHelper extends ActionCosts, Helper {
static boolean isFlowing(IBlockState state) { static boolean isFlowing(IBlockState state) {
// Will be IFluidState in 1.13 // Will be IFluidState in 1.13
return state.getBlock() instanceof BlockLiquid return state.getBlock() instanceof BlockLiquid
&& state.getPropertyKeys().contains(BlockLiquid.LEVEL)
&& state.getValue(BlockLiquid.LEVEL) != 0; && state.getValue(BlockLiquid.LEVEL) != 0;
} }
static PlaceResult attemptToPlaceABlock(MovementState state, IBaritone baritone, BlockPos placeAt, boolean preferDown) {
IPlayerContext ctx = baritone.getPlayerContext();
boolean found = false;
for (int i = 0; i < 5; i++) {
BlockPos against1 = placeAt.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
if (MovementHelper.canPlaceAgainst(ctx, against1)) {
//if (!((Baritone) baritone).getInventoryBehavior().selectThrowawayForLocation(placeAt.getX(), placeAt.getY(), placeAt.getZ())) { // get ready to place a throwaway block
if (!throwaway(ctx, true)) {
Helper.HELPER.logDebug("bb pls get me some blocks. dirt or cobble");
state.setStatus(MovementStatus.UNREACHABLE);
return PlaceResult.NO_OPTION;
}
double faceX = (placeAt.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (placeAt.getY() + against1.getY() + 1.0D) * 0.5D;
double faceZ = (placeAt.getZ() + against1.getZ() + 1.0D) * 0.5D;
Rotation place = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations());
RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance());
if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(placeAt)) {
state.setTarget(new MovementState.MovementTarget(place, true));
found = true;
if (!preferDown) {
// if preferDown is true, we want the last option
// if preferDown is false, we want the first
break;
}
}
}
}
if (ctx.getSelectedBlock().isPresent()) {
BlockPos selectedBlock = ctx.getSelectedBlock().get();
EnumFacing side = ctx.objectMouseOver().sideHit;
// only way for selectedBlock.equals(placeAt) to be true is if it's replacable
if (selectedBlock.equals(placeAt) || (MovementHelper.canPlaceAgainst(ctx, selectedBlock) && selectedBlock.offset(side).equals(placeAt))) {
return PlaceResult.READY_TO_PLACE;
}
}
return found ? PlaceResult.ATTEMPTING : PlaceResult.NO_OPTION;
}
enum PlaceResult {
READY_TO_PLACE, ATTEMPTING, NO_OPTION;
}
} }
@@ -20,6 +20,7 @@ package baritone.pathing.movement;
import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.Rotation; import baritone.api.utils.Rotation;
import baritone.api.utils.input.Input; import baritone.api.utils.input.Input;
import net.minecraft.util.math.Vec3d;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -28,6 +29,7 @@ import java.util.Optional;
public class MovementState { public class MovementState {
private MovementStatus status; private MovementStatus status;
private MovementTarget goal = new MovementTarget();
private MovementTarget target = new MovementTarget(); private MovementTarget target = new MovementTarget();
private final Map<Input, Boolean> inputState = new HashMap<>(); private final Map<Input, Boolean> inputState = new HashMap<>();
@@ -40,6 +42,15 @@ public class MovementState {
return status; return status;
} }
public MovementTarget getGoal() {
return this.goal;
}
public MovementState setGoal(MovementTarget goal) {
this.goal = goal;
return this;
}
public MovementTarget getTarget() { public MovementTarget getTarget() {
return this.target; return this.target;
} }
@@ -54,12 +65,23 @@ public class MovementState {
return this; return this;
} }
public boolean getInput(Input input) {
return this.inputState.getOrDefault(input, false);
}
public Map<Input, Boolean> getInputStates() { public Map<Input, Boolean> getInputStates() {
return this.inputState; return this.inputState;
} }
public static class MovementTarget { public static class MovementTarget {
/**
* Necessary movement to achieve
* <p>
* TODO: Decide desiredMovement type
*/
public Vec3d position;
/** /**
* Yaw and pitch angles that must be matched * Yaw and pitch angles that must be matched
*/ */
@@ -73,14 +95,27 @@ public class MovementState {
private boolean forceRotations; private boolean forceRotations;
public MovementTarget() { public MovementTarget() {
this(null, false); this(null, null, false);
}
public MovementTarget(Vec3d position) {
this(position, null, false);
} }
public MovementTarget(Rotation rotation, boolean forceRotations) { public MovementTarget(Rotation rotation, boolean forceRotations) {
this(null, rotation, forceRotations);
}
public MovementTarget(Vec3d position, Rotation rotation, boolean forceRotations) {
this.position = position;
this.rotation = rotation; this.rotation = rotation;
this.forceRotations = forceRotations; this.forceRotations = forceRotations;
} }
public final Optional<Vec3d> getPosition() {
return Optional.ofNullable(this.position);
}
public final Optional<Rotation> getRotation() { public final Optional<Rotation> getRotation() {
return Optional.ofNullable(this.rotation); return Optional.ofNullable(this.rotation);
} }
@@ -220,59 +220,51 @@ public enum Moves {
} }
}, },
DIAGONAL_NORTHEAST(+1, 0, -1, false, true) { DIAGONAL_NORTHEAST(+1, 0, -1) {
@Override @Override
public Movement apply0(CalculationContext context, BetterBlockPos src) { public Movement apply0(CalculationContext context, BetterBlockPos src) {
MutableMoveResult res = new MutableMoveResult(); return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.EAST);
apply(context, src.x, src.y, src.z, res);
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.EAST, res.y - src.y);
} }
@Override @Override
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { public double cost(CalculationContext context, int x, int y, int z) {
MovementDiagonal.cost(context, x, y, z, x + 1, z - 1, result); return MovementDiagonal.cost(context, x, y, z, x + 1, z - 1);
} }
}, },
DIAGONAL_NORTHWEST(-1, 0, -1, false, true) { DIAGONAL_NORTHWEST(-1, 0, -1) {
@Override @Override
public Movement apply0(CalculationContext context, BetterBlockPos src) { public Movement apply0(CalculationContext context, BetterBlockPos src) {
MutableMoveResult res = new MutableMoveResult(); return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.WEST);
apply(context, src.x, src.y, src.z, res);
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.WEST, res.y - src.y);
} }
@Override @Override
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { public double cost(CalculationContext context, int x, int y, int z) {
MovementDiagonal.cost(context, x, y, z, x - 1, z - 1, result); return MovementDiagonal.cost(context, x, y, z, x - 1, z - 1);
} }
}, },
DIAGONAL_SOUTHEAST(+1, 0, +1, false, true) { DIAGONAL_SOUTHEAST(+1, 0, +1) {
@Override @Override
public Movement apply0(CalculationContext context, BetterBlockPos src) { public Movement apply0(CalculationContext context, BetterBlockPos src) {
MutableMoveResult res = new MutableMoveResult(); return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.EAST);
apply(context, src.x, src.y, src.z, res);
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.EAST, res.y - src.y);
} }
@Override @Override
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { public double cost(CalculationContext context, int x, int y, int z) {
MovementDiagonal.cost(context, x, y, z, x + 1, z + 1, result); return MovementDiagonal.cost(context, x, y, z, x + 1, z + 1);
} }
}, },
DIAGONAL_SOUTHWEST(-1, 0, +1, false, true) { DIAGONAL_SOUTHWEST(-1, 0, +1) {
@Override @Override
public Movement apply0(CalculationContext context, BetterBlockPos src) { public Movement apply0(CalculationContext context, BetterBlockPos src) {
MutableMoveResult res = new MutableMoveResult(); return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.WEST);
apply(context, src.x, src.y, src.z, res);
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.WEST, res.y - src.y);
} }
@Override @Override
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { public double cost(CalculationContext context, int x, int y, int z) {
MovementDiagonal.cost(context, x, y, z, x - 1, z + 1, result); return MovementDiagonal.cost(context, x, y, z, x - 1, z + 1);
} }
}, },
@@ -21,6 +21,7 @@ import baritone.Baritone;
import baritone.api.IBaritone; import baritone.api.IBaritone;
import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.input.Input; import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
@@ -31,6 +32,10 @@ import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import java.util.Objects;
public class MovementAscend extends Movement { public class MovementAscend extends Movement {
@@ -47,28 +52,41 @@ public class MovementAscend extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z, dest.x, dest.z); return cost(context, src.x, src.y, src.z, dest.x, dest.z);
} }
public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
IBlockState srcDown = context.get(x, y - 1, z);
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
return COST_INF;
}
// we can jump from soul sand, but not from a bottom slab
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
IBlockState toPlace = context.get(destX, y, destZ); IBlockState toPlace = context.get(destX, y, destZ);
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
}
boolean hasToPlace = false; boolean hasToPlace = false;
if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) { if (!MovementHelper.canWalkOn(context.bsi(), destX, y, destZ, toPlace)) {
if (!context.canPlaceThrowawayAt(destX, y, destZ)) { if (!context.canPlaceThrowawayAt(destX, y, destZ)) {
return COST_INF; return COST_INF;
} }
if (!MovementHelper.isReplacable(destX, y, destZ, toPlace, context.bsi)) { if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace, context.world())) {
return COST_INF; return COST_INF;
} }
for (int i = 0; i < 5; i++) { // TODO: add ability to place against .down() as well as the cardinal directions
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset(); // useful for when you are starting a staircase without anything to place against
int againstY = y + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset(); // Counterpoint to the above TODO ^ you should move then pillar instead of ascend
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset(); for (int i = 0; i < 4; i++) {
if (againstX == x && againstZ == z) { // we might be able to backplace now, but it doesn't matter because it will have been broken by the time we'd need to use it int againstX = destX + HORIZONTALS[i].getXOffset();
int againstZ = destZ + HORIZONTALS[i].getZOffset();
if (againstX == x && againstZ == z) {
continue; continue;
} }
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y, againstZ)) {
hasToPlace = true; hasToPlace = true;
break; break;
} }
@@ -77,8 +95,8 @@ public class MovementAscend extends Movement {
return COST_INF; return COST_INF;
} }
} }
IBlockState srcUp2 = context.get(x, y + 2, z); // used lower down anyway IBlockState srcUp2 = null;
if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context.bsi, x, y + 1, z) || !(srcUp2.getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context.bsi(), x, y + 1, z) || !((srcUp2 = context.get(x, y + 2, z)).getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us
// HOWEVER, we assume that we're standing in the start position // HOWEVER, we assume that we're standing in the start position
// that means that src and src.up(1) are both air // that means that src and src.up(1) are both air
// maybe they aren't now, but they will be by the time this starts // maybe they aren't now, but they will be by the time this starts
@@ -96,41 +114,32 @@ public class MovementAscend extends Movement {
// it's possible srcUp is AIR from the start, and srcUp2 is falling // it's possible srcUp is AIR from the start, and srcUp2 is falling
// and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us // and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us
} }
IBlockState srcDown = context.get(x, y - 1, z);
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
return COST_INF;
}
// we can jump from soul sand, but not from a bottom slab
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
}
double walk; double walk;
if (jumpingToBottomSlab) { if (jumpingToBottomSlab) {
if (jumpingFromBottomSlab) { if (jumpingFromBottomSlab) {
walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); // we hit space immediately on entering this action walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); // we hit space immediately on entering this action
walk += context.jumpPenalty;
} else { } else {
walk = WALK_ONE_BLOCK_COST; // we don't hit space we just walk into the slab walk = WALK_ONE_BLOCK_COST; // we don't hit space we just walk into the slab
} }
} else { } else {
// jumpingFromBottomSlab must be false
if (toPlace.getBlock() == Blocks.SOUL_SAND) { if (toPlace.getBlock() == Blocks.SOUL_SAND) {
walk = WALK_ONE_OVER_SOUL_SAND_COST; walk = WALK_ONE_OVER_SOUL_SAND_COST;
} else { } else {
walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); walk = WALK_ONE_BLOCK_COST;
} }
walk += context.jumpPenalty;
} }
double totalCost = walk; // cracks knuckles
double totalCost = 0;
totalCost += walk;
if (hasToPlace) { if (hasToPlace) {
totalCost += context.placeBlockCost; totalCost += context.placeBlockCost();
} }
// start with srcUp2 since we already have its state if (srcUp2 == null) {
// includeFalling isn't needed because of the falling check above -- if srcUp3 is falling we will have already exited with COST_INF if we'd actually have to break it srcUp2 = context.get(x, y + 2, z);
totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false); }
totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false); // TODO MAKE ABSOLUTELY SURE we don't need includeFalling here, from the falling check above
if (totalCost >= COST_INF) { if (totalCost >= COST_INF) {
return COST_INF; return COST_INF;
} }
@@ -157,30 +166,55 @@ public class MovementAscend extends Movement {
IBlockState jumpingOnto = BlockStateInterface.get(ctx, positionToPlace); IBlockState jumpingOnto = BlockStateInterface.get(ctx, positionToPlace);
if (!MovementHelper.canWalkOn(ctx, positionToPlace, jumpingOnto)) { if (!MovementHelper.canWalkOn(ctx, positionToPlace, jumpingOnto)) {
ticksWithoutPlacement++; for (int i = 0; i < 4; i++) {
if (MovementHelper.attemptToPlaceABlock(state, baritone, dest.down(), false) == PlaceResult.READY_TO_PLACE) { BlockPos anAgainst = positionToPlace.offset(HORIZONTALS[i]);
state.setInput(Input.SNEAK, true); if (anAgainst.equals(src)) {
if (ctx.player().isSneaking()) { continue;
state.setInput(Input.CLICK_RIGHT, true); }
if (MovementHelper.canPlaceAgainst(ctx, anAgainst)) {
if (!MovementHelper.throwaway(ctx, true)) {//get ready to place a throwaway block
return state.setStatus(MovementStatus.UNREACHABLE);
}
double faceX = (dest.getX() + anAgainst.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + anAgainst.getY()) * 0.5D;
double faceZ = (dest.getZ() + anAgainst.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations()), true));
EnumFacing side = ctx.objectMouseOver().sideHit;
ctx.getSelectedBlock().ifPresent(selectedBlock -> {
if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionToPlace)) {
ticksWithoutPlacement++;
state.setInput(Input.SNEAK, true);
if (ctx.player().isSneaking()) {
state.setInput(Input.CLICK_RIGHT, true);
}
if (ticksWithoutPlacement > 10) {
// After 10 ticks without placement, we might be standing in the way, move back
state.setInput(Input.MOVE_BACK, true);
}
} else {
state.setInput(Input.CLICK_LEFT, true); // break whatever replaceable block is in the way
}
//System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
});
return state;
} }
} }
if (ticksWithoutPlacement > 10) { return state.setStatus(MovementStatus.UNREACHABLE);
// After 10 ticks without placement, we might be standing in the way, move back
state.setInput(Input.MOVE_BACK, true);
}
return state;
} }
MovementHelper.moveTowards(ctx, state, dest); MovementHelper.moveTowards(ctx, state, dest);
if (MovementHelper.isBottomSlab(jumpingOnto) && !MovementHelper.isBottomSlab(BlockStateInterface.get(ctx, src.down()))) { if (MovementHelper.isBottomSlab(jumpingOnto) && !MovementHelper.isBottomSlab(BlockStateInterface.get(ctx, src.down()))) {
return state; // don't jump while walking from a non double slab into a bottom slab return state; // don't jump while walking from a non double slab into a bottom slab
} }
if (Baritone.settings().assumeStep.get() || ctx.playerFeet().equals(src.up())) { if (Baritone.settings().assumeStep.get()) {
// no need to hit space if we're already jumping
return state; return state;
} }
if (ctx.playerFeet().equals(src.up())) {
return state; // no need to hit space if we're already jumping
}
if (headBonkClear()) { if (headBonkClear()) {
return state.setInput(Input.JUMP, true); return state.setInput(Input.JUMP, true);
} }
@@ -17,6 +17,7 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.IBaritone; import baritone.api.IBaritone;
import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
@@ -52,7 +53,7 @@ public class MovementDescend extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
MutableMoveResult result = new MutableMoveResult(); MutableMoveResult result = new MutableMoveResult();
cost(context, src.x, src.y, src.z, dest.x, dest.z, result); cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
if (result.y != dest.y) { if (result.y != dest.y) {
@@ -62,6 +63,11 @@ public class MovementDescend extends Movement {
} }
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) { public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) {
Block fromDown = context.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return;
}
double totalCost = 0; double totalCost = 0;
IBlockState destDown = context.get(destX, y - 1, destZ); IBlockState destDown = context.get(destX, y - 1, destZ);
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false); totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false);
@@ -77,11 +83,6 @@ public class MovementDescend extends Movement {
return; return;
} }
Block fromDown = context.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return;
}
// A // A
//SA //SA
// A // A
@@ -93,7 +94,7 @@ public class MovementDescend extends Movement {
//C, D, etc determine the length of the fall //C, D, etc determine the length of the fall
IBlockState below = context.get(destX, y - 2, destZ); IBlockState below = context.get(destX, y - 2, destZ);
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ, below)) { if (!MovementHelper.canWalkOn(context.bsi(), destX, y - 2, destZ, below)) {
dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res); dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res);
return; return;
} }
@@ -106,7 +107,7 @@ public class MovementDescend extends Movement {
double walk = WALK_OFF_BLOCK_COST; double walk = WALK_OFF_BLOCK_COST;
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance // use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST; walk = WALK_ONE_OVER_SOUL_SAND_COST;
} }
totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST); totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
res.x = destX; res.x = destX;
@@ -115,81 +116,66 @@ public class MovementDescend extends Movement {
res.cost = totalCost; res.cost = totalCost;
} }
public static boolean dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) { public static void dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
if (frontBreak != 0 && context.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) { if (frontBreak != 0 && context.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) {
// if frontBreak is 0 we can actually get through this without updating the falling block and making it actually fall // if frontBreak is 0 we can actually get through this without updating the falling block and making it actually fall
// but if frontBreak is nonzero, we're breaking blocks in front, so don't let anything fall through this column, // but if frontBreak is nonzero, we're breaking blocks in front, so don't let anything fall through this column,
// and potentially replace the water we're going to fall into // and potentially replace the water we're going to fall into
return false; return;
} }
if (!MovementHelper.canWalkThrough(context.bsi, destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) { if (!MovementHelper.canWalkThrough(context.bsi(), destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
return false; return;
} }
double costSoFar = 0;
int effectiveStartHeight = y;
for (int fallHeight = 3; true; fallHeight++) { for (int fallHeight = 3; true; fallHeight++) {
int newY = y - fallHeight; int newY = y - fallHeight;
if (newY < 0) { if (newY < 0) {
// when pathing in the end, where you could plausibly fall into the void // when pathing in the end, where you could plausibly fall into the void
// this check prevents it from getting the block at y=-1 and crashing // this check prevents it from getting the block at y=-1 and crashing
return false; return;
} }
IBlockState ontoBlock = context.get(destX, newY, destZ); IBlockState ontoBlock = context.get(destX, newY, destZ);
int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak;
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar; if (ontoBlock.getBlock() == Blocks.WATER && !MovementHelper.isFlowing(ontoBlock) && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here?
if ((ontoBlock.getBlock() == Blocks.WATER || ontoBlock.getBlock() == Blocks.FLOWING_WATER) && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) {
// lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad // lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad
// however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works) // however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works)
if (context.assumeWalkOnWater) { if (Baritone.settings().assumeWalkOnWater.get()) {
return false; // TODO fix return; // TODO fix
}
if (MovementHelper.isFlowing(ontoBlock)) {
return false; // TODO flowing check required here?
}
if (!MovementHelper.canWalkOn(context.bsi, destX, newY - 1, destZ)) {
// we could punch right through the water into something else
return false;
} }
// found a fall into water // found a fall into water
res.x = destX; res.x = destX;
res.y = newY; res.y = newY;
res.z = destZ; res.z = destZ;
res.cost = tentativeCost;// TODO incorporate water swim up cost? res.cost = tentativeCost;// TODO incorporate water swim up cost?
return false; return;
} }
if (unprotectedFallHeight <= 11 && (ontoBlock.getBlock() == Blocks.VINE || ontoBlock.getBlock() == Blocks.LADDER)) { if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) {
// if fall height is greater than or equal to 11, we don't actually grab on to vines or ladders. the more you know return;
// this effectively "resets" our falling speed }
costSoFar += FALL_N_BLOCKS_COST[unprotectedFallHeight - 1];// we fall until the top of this block (not including this block) if (MovementHelper.canWalkThrough(context.bsi(), destX, newY, destZ, ontoBlock)) {
costSoFar += LADDER_DOWN_ONE_COST;
effectiveStartHeight = newY;
continue; continue;
} }
if (MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) { if (!MovementHelper.canWalkOn(context.bsi(), destX, newY, destZ, ontoBlock)) {
continue; return;
}
if (!MovementHelper.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) {
return false;
} }
if (MovementHelper.isBottomSlab(ontoBlock)) { if (MovementHelper.isBottomSlab(ontoBlock)) {
return false; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect return; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
} }
if (unprotectedFallHeight <= context.maxFallHeightNoWater + 1) { if (context.hasWaterBucket() && fallHeight <= context.maxFallHeightBucket() + 1) {
res.x = destX;
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
res.z = destZ;
res.cost = tentativeCost + context.placeBlockCost();
return;
}
if (fallHeight <= context.maxFallHeightNoWater() + 1) {
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max // fallHeight = 4 means onto.up() is 3 blocks down, which is the max
res.x = destX; res.x = destX;
res.y = newY + 1; res.y = newY + 1;
res.z = destZ; res.z = destZ;
res.cost = tentativeCost; res.cost = tentativeCost;
return false; return;
}
if (context.hasWaterBucket && unprotectedFallHeight <= context.maxFallHeightBucket + 1) {
res.x = destX;
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
res.z = destZ;
res.cost = tentativeCost + context.placeBlockCost;
return true;
} else { } else {
return false; return;
} }
} }
} }
@@ -232,7 +218,8 @@ public class MovementDescend extends Movement {
if (numTicks++ < 20) { if (numTicks++ < 20) {
MovementHelper.moveTowards(ctx, state, fakeDest); MovementHelper.moveTowards(ctx, state, fakeDest);
if (fromStart > 1.25) { if (fromStart > 1.25) {
state.getTarget().rotation = new Rotation(state.getTarget().rotation.getYaw() + 180F, state.getTarget().rotation.getPitch()); state.setInput(Input.MOVE_FORWARD, false);
state.setInput(Input.MOVE_BACK, true);
} }
} else { } else {
MovementHelper.moveTowards(ctx, state, dest); MovementHelper.moveTowards(ctx, state, dest);
@@ -25,8 +25,6 @@ import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
@@ -40,13 +38,13 @@ public class MovementDiagonal extends Movement {
private static final double SQRT_2 = Math.sqrt(2); private static final double SQRT_2 = Math.sqrt(2);
public MovementDiagonal(IBaritone baritone, BetterBlockPos start, EnumFacing dir1, EnumFacing dir2, int dy) { public MovementDiagonal(IBaritone baritone, BetterBlockPos start, EnumFacing dir1, EnumFacing dir2) {
this(baritone, start, start.offset(dir1), start.offset(dir2), dir2, dy); this(baritone, start, start.offset(dir1), start.offset(dir2), dir2);
// super(start, start.offset(dir1).offset(dir2), new BlockPos[]{start.offset(dir1), start.offset(dir1).up(), start.offset(dir2), start.offset(dir2).up(), start.offset(dir1).offset(dir2), start.offset(dir1).offset(dir2).up()}, new BlockPos[]{start.offset(dir1).offset(dir2).down()}); // super(start, start.offset(dir1).offset(dir2), new BlockPos[]{start.offset(dir1), start.offset(dir1).up(), start.offset(dir2), start.offset(dir2).up(), start.offset(dir1).offset(dir2), start.offset(dir1).offset(dir2).up()}, new BlockPos[]{start.offset(dir1).offset(dir2).down()});
} }
private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos dir1, BetterBlockPos dir2, EnumFacing drr2, int dy) { private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos dir1, BetterBlockPos dir2, EnumFacing drr2) {
this(baritone, start, dir1.offset(drr2).up(dy), dir1, dir2); this(baritone, start, dir1.offset(drr2), dir1, dir2);
} }
private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos end, BetterBlockPos dir1, BetterBlockPos dir2) { private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos end, BetterBlockPos dir1, BetterBlockPos dir2) {
@@ -54,49 +52,38 @@ public class MovementDiagonal extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
MutableMoveResult result = new MutableMoveResult(); return cost(context, src.x, src.y, src.z, dest.x, dest.z);
cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
if (result.y != dest.y) {
return COST_INF; // doesn't apply to us, this position is incorrect
}
return result.cost;
} }
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) { public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
Block fromDown = context.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF;
}
IBlockState destInto = context.get(destX, y, destZ); IBlockState destInto = context.get(destX, y, destZ);
if (!MovementHelper.canWalkThrough(context.bsi, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi, destX, y + 1, destZ)) { if (!MovementHelper.canWalkThrough(context.bsi(), destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi(), destX, y + 1, destZ)) {
return; return COST_INF;
} }
IBlockState destWalkOn = context.get(destX, y - 1, destZ); IBlockState destWalkOn = context.get(destX, y - 1, destZ);
boolean descend = false; if (!MovementHelper.canWalkOn(context.bsi(), destX, y - 1, destZ, destWalkOn)) {
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn)) { return COST_INF;
descend = true;
if (!context.allowDiagonalDescend || !MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context.bsi, destX, y - 1, destZ, destWalkOn)) {
return;
}
} }
double multiplier = WALK_ONE_BLOCK_COST; double multiplier = WALK_ONE_BLOCK_COST;
// For either possible soul sand, that affects half of our walking // For either possible soul sand, that affects half of our walking
if (destWalkOn.getBlock() == Blocks.SOUL_SAND) { if (destWalkOn.getBlock() == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} else if (destWalkOn.getBlock() == Blocks.WATER) {
multiplier += context.walkOnWaterOnePenalty * SQRT_2;
}
Block fromDown = context.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return;
} }
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
Block cuttingOver1 = context.get(x, y - 1, destZ).getBlock(); Block cuttingOver1 = context.get(x, y - 1, destZ).getBlock();
if (cuttingOver1 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver1)) { if (cuttingOver1 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver1)) {
return; return COST_INF;
} }
Block cuttingOver2 = context.get(destX, y - 1, z).getBlock(); Block cuttingOver2 = context.get(destX, y - 1, z).getBlock();
if (cuttingOver2 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver2)) { if (cuttingOver2 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver2)) {
return; return COST_INF;
} }
IBlockState pb0 = context.get(x, y, destZ); IBlockState pb0 = context.get(x, y, destZ);
IBlockState pb2 = context.get(destX, y, z); IBlockState pb2 = context.get(destX, y, z);
@@ -105,61 +92,46 @@ public class MovementDiagonal extends Movement {
if (optionA != 0 && optionB != 0) { if (optionA != 0 && optionB != 0) {
// check these one at a time -- if pb0 and pb2 were nonzero, we already know that (optionA != 0 && optionB != 0) // check these one at a time -- if pb0 and pb2 were nonzero, we already know that (optionA != 0 && optionB != 0)
// so no need to check pb1 as well, might as well return early here // so no need to check pb1 as well, might as well return early here
return; return COST_INF;
} }
IBlockState pb1 = context.get(x, y + 1, destZ); IBlockState pb1 = context.get(x, y + 1, destZ);
optionA += MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true); optionA += MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
if (optionA != 0 && optionB != 0) { if (optionA != 0 && optionB != 0) {
// same deal, if pb1 makes optionA nonzero and option B already was nonzero, pb3 can't affect the result // same deal, if pb1 makes optionA nonzero and option B already was nonzero, pb3 can't affect the result
return; return COST_INF;
} }
IBlockState pb3 = context.get(destX, y + 1, z); IBlockState pb3 = context.get(destX, y + 1, z);
if (optionA == 0 && ((MovementHelper.avoidWalkingInto(pb2.getBlock()) && pb2.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb3.getBlock()) && pb3.getBlock() != Blocks.WATER))) { if (optionA == 0 && ((MovementHelper.avoidWalkingInto(pb2.getBlock()) && pb2.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb3.getBlock()) && pb3.getBlock() != Blocks.WATER))) {
// at this point we're done calculating optionA, so we can check if it's actually possible to edge around in that direction // at this point we're done calculating optionA, so we can check if it's actually possible to edge around in that direction
return; return COST_INF;
} }
optionB += MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true); optionB += MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true);
if (optionA != 0 && optionB != 0) { if (optionA != 0 && optionB != 0) {
// and finally, if the cost is nonzero for both ways to approach this diagonal, it's not possible // and finally, if the cost is nonzero for both ways to approach this diagonal, it's not possible
return; return COST_INF;
} }
if (optionB == 0 && ((MovementHelper.avoidWalkingInto(pb0.getBlock()) && pb0.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb1.getBlock()) && pb1.getBlock() != Blocks.WATER))) { if (optionB == 0 && ((MovementHelper.avoidWalkingInto(pb0.getBlock()) && pb0.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb1.getBlock()) && pb1.getBlock() != Blocks.WATER))) {
// and now that option B is fully calculated, see if we can edge around that way // and now that option B is fully calculated, see if we can edge around that way
return; return COST_INF;
} }
boolean water = false; boolean water = false;
Block startIn = context.getBlock(x, y, z); if (MovementHelper.isWater(context.getBlock(x, y, z)) || MovementHelper.isWater(destInto.getBlock())) {
if (MovementHelper.isWater(startIn) || MovementHelper.isWater(destInto.getBlock())) {
// Ignore previous multiplier // Ignore previous multiplier
// Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water // Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// Not even touching the blocks below // Not even touching the blocks below
multiplier = context.waterWalkSpeed; multiplier = context.waterWalkSpeed();
water = true; water = true;
} }
if (optionA != 0 || optionB != 0) { if (optionA != 0 || optionB != 0) {
multiplier *= SQRT_2 - 0.001; // TODO tune multiplier *= SQRT_2 - 0.001; // TODO tune
if (startIn == Blocks.LADDER || startIn == Blocks.VINE) {
// edging around doesn't work if doing so would climb a ladder or vine instead of moving sideways
return;
}
} else {
// only can sprint if not edging around
if (context.canSprint && !water) {
// If we aren't edging around anything, and we aren't in water
// We can sprint =D
// Don't check for soul sand, since we can sprint on that too
multiplier *= SPRINT_MULTIPLIER;
}
} }
res.cost = multiplier * SQRT_2; if (context.canSprint() && !water) {
if (descend) { // If we aren't edging around anything, and we aren't in water
res.cost += Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST); // We can sprint =D
res.y = y - 1; // Don't check for soul sand, since we can sprint on that too
} else { multiplier *= SPRINT_MULTIPLIER;
res.y = y;
} }
res.x = destX; return multiplier * SQRT_2;
res.z = destZ;
} }
@Override @Override
@@ -186,13 +158,13 @@ public class MovementDiagonal extends Movement {
} }
@Override @Override
public List<BlockPos> toBreak(BlockStateInterface bsi) { public List<BlockPos> toBreak() {
if (toBreakCached != null) { if (toBreakCached != null) {
return toBreakCached; return toBreakCached;
} }
List<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (int i = 4; i < 6; i++) { for (int i = 4; i < 6; i++) {
if (!MovementHelper.canWalkThrough(bsi, positionsToBreak[i].x, positionsToBreak[i].y, positionsToBreak[i].z)) { if (!MovementHelper.canWalkThrough(ctx, positionsToBreak[i])) {
result.add(positionsToBreak[i]); result.add(positionsToBreak[i]);
} }
} }
@@ -201,13 +173,13 @@ public class MovementDiagonal extends Movement {
} }
@Override @Override
public List<BlockPos> toWalkInto(BlockStateInterface bsi) { public List<BlockPos> toWalkInto() {
if (toWalkIntoCached == null) { if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>(); toWalkIntoCached = new ArrayList<>();
} }
List<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (!MovementHelper.canWalkThrough(bsi, positionsToBreak[i].x, positionsToBreak[i].y, positionsToBreak[i].z)) { if (!MovementHelper.canWalkThrough(ctx, positionsToBreak[i])) {
result.add(positionsToBreak[i]); result.add(positionsToBreak[i]);
} }
} }
@@ -43,21 +43,22 @@ public class MovementDownward extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z); return cost(context, src.x, src.y, src.z);
} }
public static double cost(CalculationContext context, int x, int y, int z) { public static double cost(CalculationContext context, int x, int y, int z) {
if (!MovementHelper.canWalkOn(context.bsi, x, y - 2, z)) { if (!MovementHelper.canWalkOn(context.bsi(), x, y - 2, z)) {
return COST_INF; return COST_INF;
} }
IBlockState down = context.get(x, y - 1, z); IBlockState d = context.get(x, y - 1, z);
Block downBlock = down.getBlock(); Block td = d.getBlock();
if (downBlock == Blocks.LADDER || downBlock == Blocks.VINE) { boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
if (ladder) {
return LADDER_DOWN_ONE_COST; return LADDER_DOWN_ONE_COST;
} else { } else {
// we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement // we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, x, y - 1, z, down, false); return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, x, y - 1, z, d, false);
} }
} }
@@ -17,6 +17,7 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.IBaritone; import baritone.api.IBaritone;
import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
@@ -30,20 +31,12 @@ import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.pathing.MutableMoveResult; import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items; import net.minecraft.init.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import java.util.Optional;
public class MovementFall extends Movement { public class MovementFall extends Movement {
@@ -55,7 +48,7 @@ public class MovementFall extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
MutableMoveResult result = new MutableMoveResult(); MutableMoveResult result = new MutableMoveResult();
MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z, result); MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
if (result.y != dest.y) { if (result.y != dest.y) {
@@ -64,12 +57,6 @@ public class MovementFall extends Movement {
return result.cost; return result.cost;
} }
private boolean willPlaceBucket() {
CalculationContext context = new CalculationContext(baritone);
MutableMoveResult result = new MutableMoveResult();
return MovementDescend.dynamicFallCost(context, src.x, src.y, src.z, dest.x, dest.z, 0, context.get(dest.x, src.y - 2, dest.z), result);
}
@Override @Override
public MovementState updateState(MovementState state) { public MovementState updateState(MovementState state) {
super.updateState(state); super.updateState(state);
@@ -80,9 +67,7 @@ public class MovementFall extends Movement {
BlockPos playerFeet = ctx.playerFeet(); BlockPos playerFeet = ctx.playerFeet();
Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest)); Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest));
Rotation targetRotation = null; Rotation targetRotation = null;
Block destBlock = ctx.world().getBlockState(dest).getBlock(); if (!MovementHelper.isWater(ctx, dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) {
boolean isWater = destBlock == Blocks.WATER || destBlock == Blocks.FLOWING_WATER;
if (!isWater && willPlaceBucket() && !playerFeet.equals(dest)) {
if (!InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_WATER)) || ctx.world().provider.isNether()) { if (!InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_WATER)) || ctx.world().provider.isNether()) {
return state.setStatus(MovementStatus.UNREACHABLE); return state.setStatus(MovementStatus.UNREACHABLE);
} }
@@ -93,7 +78,7 @@ public class MovementFall extends Movement {
targetRotation = new Rotation(toDest.getYaw(), 90.0F); targetRotation = new Rotation(toDest.getYaw(), 90.0F);
RayTraceResult trace = ctx.objectMouseOver(); RayTraceResult trace = ctx.objectMouseOver();
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && (trace.getBlockPos().equals(dest) || trace.getBlockPos().equals(dest.down()))) { if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && ctx.player().rotationPitch > 89.0F) {
state.setInput(Input.CLICK_RIGHT, true); state.setInput(Input.CLICK_RIGHT, true);
} }
} }
@@ -103,8 +88,8 @@ public class MovementFall extends Movement {
} else { } else {
state.setTarget(new MovementTarget(toDest, false)); state.setTarget(new MovementTarget(toDest, false));
} }
if (playerFeet.equals(dest) && (ctx.player().posY - playerFeet.getY() < 0.094 || isWater)) { // 0.094 because lilypads if (playerFeet.equals(dest) && (ctx.player().posY - playerFeet.getY() < 0.094 || MovementHelper.isWater(ctx, dest))) { // 0.094 because lilypads
if (isWater) { // only match water, not flowing water (which we cannot pick up with a bucket) if (MovementHelper.isWater(ctx, dest)) {
if (InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_EMPTY))) { if (InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_EMPTY))) {
ctx.player().inventory.currentItem = ctx.player().inventory.getSlotFor(STACK_BUCKET_EMPTY); ctx.player().inventory.currentItem = ctx.player().inventory.getSlotFor(STACK_BUCKET_EMPTY);
if (ctx.player().motionY >= 0) { if (ctx.player().motionY >= 0) {
@@ -122,40 +107,12 @@ public class MovementFall extends Movement {
} }
} }
Vec3d destCenter = VecUtils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder) Vec3d destCenter = VecUtils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder)
if (Math.abs(ctx.player().posX + ctx.player().motionX - destCenter.x) > 0.1 || Math.abs(ctx.player().posZ + ctx.player().motionZ - destCenter.z) > 0.1) { if (Math.abs(ctx.player().posX - destCenter.x) > 0.15 || Math.abs(ctx.player().posZ - destCenter.z) > 0.15) {
if (!ctx.player().onGround && Math.abs(ctx.player().motionY) > 0.4) {
state.setInput(Input.SNEAK, true);
}
state.setInput(Input.MOVE_FORWARD, true); state.setInput(Input.MOVE_FORWARD, true);
} }
Vec3i avoid = Optional.ofNullable(avoid()).map(EnumFacing::getDirectionVec).orElse(null);
if (avoid == null) {
avoid = src.subtract(dest);
} else {
double dist = Math.abs(avoid.getX() * (destCenter.x - avoid.getX() / 2.0 - ctx.player().posX)) + Math.abs(avoid.getZ() * (destCenter.z - avoid.getZ() / 2.0 - ctx.player().posZ));
if (dist < 0.6) {
state.setInput(Input.MOVE_FORWARD, true);
} else if (!ctx.player().onGround) {
state.setInput(Input.SNEAK, false);
}
}
if (targetRotation == null) {
Vec3d destCenterOffset = new Vec3d(destCenter.x + 0.125 * avoid.getX(), destCenter.y, destCenter.z + 0.125 * avoid.getZ());
state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), destCenterOffset), false));
}
return state; return state;
} }
private EnumFacing avoid() {
for (int i = 0; i < 15; i++) {
IBlockState state = ctx.world().getBlockState(ctx.playerFeet().down(i));
if (state.getBlock() == Blocks.LADDER) {
return state.getValue(BlockLadder.FACING);
}
}
return null;
}
@Override @Override
public boolean safeToCancel(MovementState state) { public boolean safeToCancel(MovementState state) {
// if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall // if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall
@@ -17,24 +17,35 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.IBaritone; import baritone.api.IBaritone;
import baritone.api.pathing.movement.MovementStatus; import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RayTraceUtils;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.input.Input; import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.pathing.MutableMoveResult; import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockStairs; import net.minecraft.block.BlockStairs;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import java.util.Objects;
public class MovementParkour extends Movement { public class MovementParkour extends Movement {
private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN};
private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{}; private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{};
private final EnumFacing direction; private final EnumFacing direction;
@@ -54,25 +65,24 @@ public class MovementParkour extends Movement {
} }
public static void cost(CalculationContext context, int x, int y, int z, EnumFacing dir, MutableMoveResult res) { public static void cost(CalculationContext context, int x, int y, int z, EnumFacing dir, MutableMoveResult res) {
if (!context.allowParkour) { if (!Baritone.settings().allowParkour.get()) {
return; return;
} }
if (y == 256 && !context.allowJumpAt256) { IBlockState standingOn = context.get(x, y - 1, z);
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof BlockStairs || MovementHelper.isBottomSlab(standingOn)) {
return;
}
int xDiff = dir.getXOffset();
int zDiff = dir.getZOffset();
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff);
if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks
return;
}
if (MovementHelper.canWalkOn(context.bsi(), x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
return; return;
} }
int xDiff = dir.getXOffset();
int zDiff = dir.getZOffset();
if (!MovementHelper.fullyPassable(context, x + xDiff, y, z + zDiff)) { if (!MovementHelper.fullyPassable(context, x + xDiff, y, z + zDiff)) {
// most common case at the top -- the adjacent block isn't air
return;
}
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff);
if (MovementHelper.canWalkOn(context.bsi, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
// second most common case -- we could just traverse not parkour
return;
}
if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks
return; return;
} }
if (!MovementHelper.fullyPassable(context, x + xDiff, y + 1, z + zDiff)) { if (!MovementHelper.fullyPassable(context, x + xDiff, y + 1, z + zDiff)) {
@@ -84,15 +94,11 @@ public class MovementParkour extends Movement {
if (!MovementHelper.fullyPassable(context, x, y + 2, z)) { if (!MovementHelper.fullyPassable(context, x, y + 2, z)) {
return; return;
} }
IBlockState standingOn = context.get(x, y - 1, z);
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof BlockStairs || MovementHelper.isBottomSlab(standingOn)) {
return;
}
int maxJump; int maxJump;
if (standingOn.getBlock() == Blocks.SOUL_SAND) { if (standingOn.getBlock() == Blocks.SOUL_SAND) {
maxJump = 2; // 1 block gap maxJump = 2; // 1 block gap
} else { } else {
if (context.canSprint) { if (context.canSprint()) {
maxJump = 4; maxJump = 4;
} else { } else {
maxJump = 3; maxJump = 3;
@@ -105,41 +111,44 @@ public class MovementParkour extends Movement {
return; return;
} }
} }
if (MovementHelper.canWalkOn(context.bsi, x + xDiff * i, y - 1, z + zDiff * i)) { if (MovementHelper.canWalkOn(context.bsi(), x + xDiff * i, y - 1, z + zDiff * i)) {
res.x = x + xDiff * i; res.x = x + xDiff * i;
res.y = y; res.y = y;
res.z = z + zDiff * i; res.z = z + zDiff * i;
res.cost = costFromJumpDistance(i) + context.jumpPenalty; res.cost = costFromJumpDistance(i);
return; return;
} }
} }
if (maxJump != 4) { if (maxJump != 4) {
return; return;
} }
if (!context.allowParkourPlace) { if (!Baritone.settings().allowParkourPlace.get()) {
return;
}
if (!Baritone.settings().allowPlace.get()) {
Helper.HELPER.logDirect("allowParkourPlace enabled but allowPlace disabled?");
return; return;
} }
int destX = x + 4 * xDiff; int destX = x + 4 * xDiff;
int destZ = z + 4 * zDiff; int destZ = z + 4 * zDiff;
IBlockState toPlace = context.get(destX, y - 1, destZ);
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) { if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
return; return;
} }
IBlockState toReplace = context.get(destX, y - 1, destZ); if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace, context.world())) {
if (!MovementHelper.isReplacable(destX, y - 1, destZ, toReplace, context.bsi)) {
return; return;
} }
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset(); int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset();
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset(); int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset();
if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast
continue; continue;
} }
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y - 1, againstZ)) {
res.x = destX; res.x = destX;
res.y = y; res.y = y;
res.z = destZ; res.z = destZ;
res.cost = costFromJumpDistance(4) + context.placeBlockCost + context.jumpPenalty; res.cost = costFromJumpDistance(4) + context.placeBlockCost();
return; return;
} }
} }
@@ -160,7 +169,7 @@ public class MovementParkour extends Movement {
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
MutableMoveResult res = new MutableMoveResult(); MutableMoveResult res = new MutableMoveResult();
cost(context, src.x, src.y, src.z, direction, res); cost(context, src.x, src.y, src.z, direction, res);
if (res.x != dest.x || res.z != dest.z) { if (res.x != dest.x || res.z != dest.z) {
@@ -203,9 +212,34 @@ public class MovementParkour extends Movement {
} }
} else if (!ctx.playerFeet().equals(src)) { } else if (!ctx.playerFeet().equals(src)) {
if (ctx.playerFeet().equals(src.offset(direction)) || ctx.player().posY - ctx.playerFeet().getY() > 0.0001) { if (ctx.playerFeet().equals(src.offset(direction)) || ctx.player().posY - ctx.playerFeet().getY() > 0.0001) {
if (!MovementHelper.canWalkOn(ctx, dest.down()) && !ctx.player().onGround && MovementHelper.attemptToPlaceABlock(state, baritone, dest.down(), true) == PlaceResult.READY_TO_PLACE) {
// go in the opposite order to check DOWN before all horizontals -- down is preferable because you don't have to look to the side while in midair, which could mess up the trajectory if (!MovementHelper.canWalkOn(ctx, dest.down()) && !ctx.player().onGround) {
state.setInput(Input.CLICK_RIGHT, true); BlockPos positionToPlace = dest.down();
for (int i = 0; i < 5; i++) {
BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast
continue;
}
if (MovementHelper.canPlaceAgainst(ctx, against1)) {
if (!MovementHelper.throwaway(ctx, true)) {//get ready to place a throwaway block
return state.setStatus(MovementStatus.UNREACHABLE);
}
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + against1.getY()) * 0.5D;
double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D;
Rotation place = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations());
RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance());
if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(dest.down())) {
state.setTarget(new MovementState.MovementTarget(place, true));
}
ctx.getSelectedBlock().ifPresent(selectedBlock -> {
EnumFacing side = ctx.objectMouseOver().sideHit;
if (Objects.equals(selectedBlock, against1) && selectedBlock.offset(side).equals(dest.down())) {
state.setInput(Input.CLICK_RIGHT, true);
}
});
}
}
} }
if (dist == 3) { // this is a 2 block gap, dest = src + direction * 3 if (dist == 3) { // this is a 2 block gap, dest = src + direction * 3
double xDiff = (src.x + 0.5) - ctx.player().posX; double xDiff = (src.x + 0.5) - ctx.player().posX;
@@ -35,8 +35,6 @@ import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import java.util.Objects;
public class MovementPillar extends Movement { public class MovementPillar extends Movement {
public MovementPillar(IBaritone baritone, BetterBlockPos start, BetterBlockPos end) { public MovementPillar(IBaritone baritone, BetterBlockPos start, BetterBlockPos end) {
@@ -44,44 +42,38 @@ public class MovementPillar extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z); return cost(context, src.x, src.y, src.z);
} }
public static double cost(CalculationContext context, int x, int y, int z) { public static double cost(CalculationContext context, int x, int y, int z) {
Block from = context.get(x, y, z).getBlock(); Block fromDown = context.get(x, y, z).getBlock();
boolean ladder = from == Blocks.LADDER || from == Blocks.VINE; boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine;
IBlockState fromDown = context.get(x, y - 1, z); IBlockState fromDownDown = context.get(x, y - 1, z);
if (!ladder) { if (!ladder) {
if (fromDown.getBlock() == Blocks.LADDER || fromDown.getBlock() == Blocks.VINE) { if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) {
return COST_INF; // can't pillar from a ladder or vine onto something that isn't also climbable return COST_INF;
} }
if (fromDown.getBlock() instanceof BlockSlab && !((BlockSlab) fromDown.getBlock()).isDouble() && fromDown.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) { if (fromDownDown.getBlock() instanceof BlockSlab && !((BlockSlab) fromDownDown.getBlock()).isDouble() && fromDownDown.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
return COST_INF; // can't pillar up from a bottom slab onto a non ladder return COST_INF; // can't pillar up from a bottom slab onto a non ladder
} }
} }
if (from == Blocks.VINE && !hasAgainst(context, x, y, z)) { // TODO this vine can't be climbed, but we could place a pillar still since vines are replacable, no? perhaps the pillar jump would be impossible because of the slowdown actually. if (fromDown instanceof BlockVine && !hasAgainst(context, x, y, z)) {
return COST_INF; return COST_INF;
} }
IBlockState toBreak = context.get(x, y + 2, z); IBlockState toBreak = context.get(x, y + 2, z);
Block toBreakBlock = toBreak.getBlock(); Block toBreakBlock = toBreak.getBlock();
if (toBreakBlock instanceof BlockFenceGate) { // see issue #172 if (toBreakBlock instanceof BlockFenceGate) {
return COST_INF; return COST_INF;
} }
Block srcUp = null; Block srcUp = null;
if (MovementHelper.isWater(toBreakBlock) && MovementHelper.isWater(from)) { // TODO should this also be allowed if toBreakBlock is air? if (MovementHelper.isWater(toBreakBlock) && MovementHelper.isWater(fromDown)) {
srcUp = context.get(x, y + 1, z).getBlock(); srcUp = context.get(x, y + 1, z).getBlock();
if (MovementHelper.isWater(srcUp)) { if (MovementHelper.isWater(srcUp)) {
return LADDER_UP_ONE_COST; // allow ascending pillars of water, but only if we're already in one return LADDER_UP_ONE_COST;
} }
} }
if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) { // we need to place a block where we started to jump on it if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) {
return COST_INF;
}
if (from instanceof BlockLiquid || (fromDown.getBlock() instanceof BlockLiquid && context.assumeWalkOnWater)) {
// otherwise, if we're standing in water, we cannot pillar
// if we're standing on water and assumeWalkOnWater is true, we cannot pillar
// if we're standing on water and assumeWalkOnWater is false, we must have ascended to here, or sneak backplaced, so it is possible to pillar again
return COST_INF; return COST_INF;
} }
double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true); double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true);
@@ -89,10 +81,10 @@ public class MovementPillar extends Movement {
return COST_INF; return COST_INF;
} }
if (hardness != 0) { if (hardness != 0) {
if (toBreakBlock == Blocks.LADDER || toBreakBlock == Blocks.VINE) { if (toBreakBlock instanceof BlockLadder || toBreakBlock instanceof BlockVine) {
hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it
} else { } else {
IBlockState check = context.get(x, y + 3, z); // the block on top of the one we're going to break, could it fall on us? IBlockState check = context.get(x, y + 3, z);
if (check.getBlock() instanceof BlockFalling) { if (check.getBlock() instanceof BlockFalling) {
// see MovementAscend's identical check for breaking a falling block above our head // see MovementAscend's identical check for breaking a falling block above our head
if (srcUp == null) { if (srcUp == null) {
@@ -111,10 +103,13 @@ public class MovementPillar extends Movement {
//} //}
} }
} }
if (fromDown instanceof BlockLiquid || fromDownDown.getBlock() instanceof BlockLiquid) {//can't pillar on water or in water
return COST_INF;
}
if (ladder) { if (ladder) {
return LADDER_UP_ONE_COST + hardness * 5; return LADDER_UP_ONE_COST + hardness * 5;
} else { } else {
return JUMP_ONE_BLOCK_COST + context.placeBlockCost + context.jumpPenalty + hardness; return JUMP_ONE_BLOCK_COST + context.placeBlockCost() + hardness;
} }
} }
@@ -161,8 +156,8 @@ public class MovementPillar extends Movement {
} }
return state; return state;
} }
boolean ladder = fromDown.getBlock() == Blocks.LADDER || fromDown.getBlock() == Blocks.VINE; boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine;
boolean vine = fromDown.getBlock() == Blocks.VINE; boolean vine = fromDown.getBlock() instanceof BlockVine;
Rotation rotation = RotationUtils.calcRotationFromVec3d(ctx.player().getPositionEyes(1.0F), Rotation rotation = RotationUtils.calcRotationFromVec3d(ctx.player().getPositionEyes(1.0F),
VecUtils.getBlockPosCenter(positionToPlace), VecUtils.getBlockPosCenter(positionToPlace),
new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch)); new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch));
@@ -226,7 +221,7 @@ public class MovementPillar extends Movement {
if (!(fr instanceof BlockAir || fr.isReplaceable(ctx.world(), src))) { if (!(fr instanceof BlockAir || fr.isReplaceable(ctx.world(), src))) {
state.setInput(Input.CLICK_LEFT, true); state.setInput(Input.CLICK_LEFT, true);
blockIsThere = false; blockIsThere = false;
} else if (ctx.player().isSneaking() && (Objects.equals(src.down(), ctx.objectMouseOver().getBlockPos()) || Objects.equals(src, ctx.objectMouseOver().getBlockPos()))) { } else if (ctx.player().isSneaking()) { // 1 tick after we're able to place
state.setInput(Input.CLICK_RIGHT, true); state.setInput(Input.CLICK_RIGHT, true);
} }
} }
@@ -30,12 +30,10 @@ import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block; import net.minecraft.block.*;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockFenceGate;
import net.minecraft.block.BlockSlab;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -59,7 +57,7 @@ public class MovementTraverse extends Movement {
} }
@Override @Override
public double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z, dest.x, dest.z); return cost(context, src.x, src.y, src.z, dest.x, dest.z);
} }
@@ -68,29 +66,27 @@ public class MovementTraverse extends Movement {
IBlockState pb1 = context.get(destX, y, destZ); IBlockState pb1 = context.get(destX, y, destZ);
IBlockState destOn = context.get(destX, y - 1, destZ); IBlockState destOn = context.get(destX, y - 1, destZ);
Block srcDown = context.getBlock(x, y - 1, z); Block srcDown = context.getBlock(x, y - 1, z);
if (MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge if (MovementHelper.canWalkOn(context.bsi(), destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
double WC = WALK_ONE_BLOCK_COST; double WC = WALK_ONE_BLOCK_COST;
boolean water = false; boolean water = false;
if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) { if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) {
WC = context.waterWalkSpeed; WC = context.waterWalkSpeed();
water = true; water = true;
} else { } else {
if (destOn.getBlock() == Blocks.SOUL_SAND) { if (destOn.getBlock() == Blocks.SOUL_SAND) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} else if (destOn.getBlock() == Blocks.WATER) {
WC += context.walkOnWaterOnePenalty;
} }
if (srcDown == Blocks.SOUL_SAND) { if (srcDown == Blocks.SOUL_SAND) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
} }
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false); double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true);
if (hardness1 >= COST_INF) { if (hardness1 >= COST_INF) {
return COST_INF; return COST_INF;
} }
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true); // only include falling on the upper block to break double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
if (hardness1 == 0 && hardness2 == 0) { if (hardness1 == 0 && hardness2 == 0) {
if (!water && context.canSprint) { if (!water && context.canSprint()) {
// If there's nothing in the way, and this isn't water, and we aren't sneak placing // If there's nothing in the way, and this isn't water, and we aren't sneak placing
// We can sprint =D // We can sprint =D
// Don't check for soul sand, since we can sprint on that too // Don't check for soul sand, since we can sprint on that too
@@ -107,43 +103,42 @@ public class MovementTraverse extends Movement {
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) { if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
return COST_INF; return COST_INF;
} }
if (MovementHelper.isReplacable(destX, y - 1, destZ, destOn, context.bsi)) { if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(destX, y - 1, destZ, destOn, context.world())) {
boolean throughWater = MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock()); boolean throughWater = MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock());
if (MovementHelper.isWater(destOn.getBlock()) && throughWater) { if (MovementHelper.isWater(destOn.getBlock()) && throughWater) {
// this happens when assume walk on water is true and this is a traverse in water, which isn't allowed
return COST_INF; return COST_INF;
} }
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) { if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
return COST_INF; return COST_INF;
} }
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false); double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb0, false);
if (hardness1 >= COST_INF) { if (hardness1 >= COST_INF) {
return COST_INF; return COST_INF;
} }
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true); // only include falling on the upper block to break double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb1, true);
double WC = throughWater ? context.waterWalkSpeed : WALK_ONE_BLOCK_COST;
for (int i = 0; i < 5; i++) { double WC = throughWater ? context.waterWalkSpeed() : WALK_ONE_BLOCK_COST;
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset(); for (int i = 0; i < 4; i++) {
int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset(); int againstX = destX + HORIZONTALS[i].getXOffset();
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset(); int againstZ = destZ + HORIZONTALS[i].getZOffset();
if (againstX == x && againstZ == z) { // this would be a backplace if (againstX == x && againstZ == z) {
continue; continue;
} }
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { // found a side place option if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y - 1, againstZ)) {
return WC + context.placeBlockCost + hardness1 + hardness2; return WC + context.placeBlockCost() + hardness1 + hardness2;
} }
} }
// now that we've checked all possible directions to side place, we actually need to backplace
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) { if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) {
return COST_INF; // can't sneak and backplace against soul sand or half slabs (regardless of whether it's top half or bottom half) =/ return COST_INF; // can't sneak and backplace against soul sand or half slabs =/
} }
if (srcDown == Blocks.FLOWING_WATER || srcDown == Blocks.WATER) { if (srcDown == Blocks.FLOWING_WATER || srcDown == Blocks.WATER) {
return COST_INF; // this is obviously impossible return COST_INF; // this is obviously impossible
} }
WC = WC * (SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST);//since we are sneak backplacing, we are sneaking lol WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking
return WC + context.placeBlockCost + hardness1 + hardness2; return WC + context.placeBlockCost() + hardness1 + hardness2;
} }
return COST_INF; return COST_INF;
// Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock());
} }
} }
@@ -185,7 +180,7 @@ public class MovementTraverse extends Movement {
state.setInput(Input.SNEAK, false); state.setInput(Input.SNEAK, false);
Block fd = BlockStateInterface.get(ctx, src.down()).getBlock(); Block fd = BlockStateInterface.get(ctx, src.down()).getBlock();
boolean ladder = fd == Blocks.LADDER || fd == Blocks.VINE; boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine;
IBlockState pb0 = BlockStateInterface.get(ctx, positionsToBreak[0]); IBlockState pb0 = BlockStateInterface.get(ctx, positionsToBreak[0]);
IBlockState pb1 = BlockStateInterface.get(ctx, positionsToBreak[1]); IBlockState pb1 = BlockStateInterface.get(ctx, positionsToBreak[1]);
@@ -238,7 +233,7 @@ public class MovementTraverse extends Movement {
state.setInput(Input.SPRINT, true); state.setInput(Input.SPRINT, true);
} }
Block destDown = BlockStateInterface.get(ctx, dest.down()).getBlock(); Block destDown = BlockStateInterface.get(ctx, dest.down()).getBlock();
if (whereAmI.getY() != dest.getY() && ladder && (destDown == Blocks.VINE || destDown == Blocks.LADDER)) { if (whereAmI.getY() != dest.getY() && ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
new MovementPillar(baritone, dest.down(), dest).updateState(state); // i'm sorry new MovementPillar(baritone, dest.down(), dest).updateState(state); // i'm sorry
return state; return state;
} }
@@ -246,45 +241,53 @@ public class MovementTraverse extends Movement {
return state; return state;
} else { } else {
wasTheBridgeBlockAlwaysThere = false; wasTheBridgeBlockAlwaysThere = false;
Block standingOn = BlockStateInterface.get(ctx, ctx.playerFeet().down()).getBlock(); for (int i = 0; i < 4; i++) {
if (standingOn.equals(Blocks.SOUL_SAND) || standingOn instanceof BlockSlab) { // see issue #118 BlockPos against1 = dest.offset(HORIZONTALS[i]);
double dist = Math.max(Math.abs(dest.getX() + 0.5 - ctx.player().posX), Math.abs(dest.getZ() + 0.5 - ctx.player().posZ)); if (against1.equals(src)) {
if (dist < 0.85) { // 0.5 + 0.3 + epsilon continue;
MovementHelper.moveTowards(ctx, state, dest);
return state.setInput(Input.MOVE_FORWARD, false)
.setInput(Input.MOVE_BACK, true);
} }
} against1 = against1.down();
double dist1 = Math.max(Math.abs(ctx.player().posX - (dest.getX() + 0.5D)), Math.abs(ctx.player().posZ - (dest.getZ() + 0.5D))); if (MovementHelper.canPlaceAgainst(ctx, against1)) {
PlaceResult p = MovementHelper.attemptToPlaceABlock(state, baritone, dest.down(), false); if (!MovementHelper.throwaway(ctx, true)) { // get ready to place a throwaway block
if ((p == PlaceResult.READY_TO_PLACE || dist1 < 0.6) && !Baritone.settings().assumeSafeWalk.get()) { logDebug("bb pls get me some blocks. dirt or cobble");
state.setInput(Input.SNEAK, true); return state.setStatus(MovementStatus.UNREACHABLE);
}
switch (p) {
case READY_TO_PLACE: {
if (ctx.player().isSneaking() || Baritone.settings().assumeSafeWalk.get()) {
state.setInput(Input.CLICK_RIGHT, true);
} }
return state; if (!Baritone.settings().assumeSafeWalk.get()) {
} state.setInput(Input.SNEAK, true);
case ATTEMPTING: { }
if (dist1 > 0.83) { Block standingOn = BlockStateInterface.get(ctx, ctx.playerFeet().down()).getBlock();
// might need to go forward a bit if (standingOn.equals(Blocks.SOUL_SAND) || standingOn instanceof BlockSlab) { // see issue #118
float yaw = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest), ctx.playerRotations()).getYaw(); double dist = Math.max(Math.abs(dest.getX() + 0.5 - ctx.player().posX), Math.abs(dest.getZ() + 0.5 - ctx.player().posZ));
if (Math.abs(state.getTarget().rotation.getYaw() - yaw) < 0.1) { if (dist < 0.85) { // 0.5 + 0.3 + epsilon
// but only if our attempted place is straight ahead MovementHelper.moveTowards(ctx, state, dest);
return state.setInput(Input.MOVE_FORWARD, true); return state.setInput(Input.MOVE_FORWARD, false)
.setInput(Input.MOVE_BACK, true);
} }
} else if (ctx.playerRotations().isReallyCloseTo(state.getTarget().rotation)) {
// well i guess theres something in the way
return state.setInput(Input.CLICK_LEFT, true);
} }
return state; state.setInput(Input.MOVE_BACK, false);
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + against1.getY()) * 0.5D;
double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations()), true));
EnumFacing side = ctx.objectMouseOver().sideHit;
if (Objects.equals(ctx.getSelectedBlock().orElse(null), against1) && (ctx.player().isSneaking() || Baritone.settings().assumeSafeWalk.get()) && ctx.getSelectedBlock().get().offset(side).equals(positionToPlace)) {
return state.setInput(Input.CLICK_RIGHT, true);
}
//System.out.println("Trying to look at " + against1 + ", actually looking at" + RayTraceUtils.getSelectedBlock());
return state.setInput(Input.CLICK_LEFT, true);
} }
} }
if (!Baritone.settings().assumeSafeWalk.get()) {
state.setInput(Input.SNEAK, true);
}
if (whereAmI.equals(dest)) { if (whereAmI.equals(dest)) {
// If we are in the block that we are trying to get to, we are sneaking over air and we need to place a block beneath us against the one we just walked off of // If we are in the block that we are trying to get to, we are sneaking over air and we need to place a block beneath us against the one we just walked off of
// Out.log(from + " " + to + " " + faceX + "," + faceY + "," + faceZ + " " + whereAmI); // Out.log(from + " " + to + " " + faceX + "," + faceY + "," + faceZ + " " + whereAmI);
if (!MovementHelper.throwaway(ctx, true)) {// get ready to place a throwaway block
logDebug("bb pls get me some blocks. dirt or cobble");
return state.setStatus(MovementStatus.UNREACHABLE);
}
double faceX = (dest.getX() + src.getX() + 1.0D) * 0.5D; double faceX = (dest.getX() + src.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + src.getY() - 1.0D) * 0.5D; double faceY = (dest.getY() + src.getY() - 1.0D) * 0.5D;
double faceZ = (dest.getZ() + src.getZ() + 1.0D) * 0.5D; double faceZ = (dest.getZ() + src.getZ() + 1.0D) * 0.5D;
@@ -293,26 +296,25 @@ public class MovementTraverse extends Movement {
Rotation backToFace = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations()); Rotation backToFace = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), new Vec3d(faceX, faceY, faceZ), ctx.playerRotations());
float pitch = backToFace.getPitch(); float pitch = backToFace.getPitch();
double dist2 = Math.max(Math.abs(ctx.player().posX - faceX), Math.abs(ctx.player().posZ - faceZ)); double dist = Math.max(Math.abs(ctx.player().posX - faceX), Math.abs(ctx.player().posZ - faceZ));
if (dist2 < 0.29) { // see issue #208 if (dist < 0.29) {
float yaw = RotationUtils.calcRotationFromVec3d(VecUtils.getBlockPosCenter(dest), ctx.playerHead(), ctx.playerRotations()).getYaw(); float yaw = RotationUtils.calcRotationFromVec3d(VecUtils.getBlockPosCenter(dest), ctx.playerHead(), ctx.playerRotations()).getYaw();
state.setTarget(new MovementState.MovementTarget(new Rotation(yaw, pitch), true)); state.setTarget(new MovementState.MovementTarget(new Rotation(yaw, pitch), true));
state.setInput(Input.MOVE_BACK, true); state.setInput(Input.MOVE_BACK, true);
} else { } else {
state.setTarget(new MovementState.MovementTarget(backToFace, true)); state.setTarget(new MovementState.MovementTarget(backToFace, true));
} }
state.setInput(Input.SNEAK, true);
if (Objects.equals(ctx.getSelectedBlock().orElse(null), goalLook)) { if (Objects.equals(ctx.getSelectedBlock().orElse(null), goalLook)) {
return state.setInput(Input.CLICK_RIGHT, true); // wait to right click until we are able to place return state.setInput(Input.CLICK_RIGHT, true); // wait to right click until we are able to place
} }
// Out.log("Trying to look at " + goalLook + ", actually looking at" + Baritone.whatAreYouLookingAt()); // Out.log("Trying to look at " + goalLook + ", actually looking at" + Baritone.whatAreYouLookingAt());
if (ctx.playerRotations().isReallyCloseTo(state.getTarget().rotation)) { return state.setInput(Input.CLICK_LEFT, true);
state.setInput(Input.CLICK_LEFT, true); } else {
} MovementHelper.moveTowards(ctx, state, positionsToBreak[0]);
return state; return state;
// TODO MovementManager.moveTowardsBlock(to); // move towards not look at because if we are bridging for a couple blocks in a row, it is faster if we dont spin around and walk forwards then spin around and place backwards for every block
} }
MovementHelper.moveTowards(ctx, state, positionsToBreak[0]);
return state;
// TODO MovementManager.moveTowardsBlock(to); // move towards not look at because if we are bridging for a couple blocks in a row, it is faster if we dont spin around and walk forwards then spin around and place backwards for every block
} }
} }
@@ -334,4 +336,4 @@ public class MovementTraverse extends Movement {
} }
return super.prepared(state); return super.prepared(state);
} }
} }
@@ -30,12 +30,10 @@ import baritone.api.utils.input.Input;
import baritone.behavior.PathingBehavior; import baritone.behavior.PathingBehavior;
import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.movements.*; import baritone.pathing.movement.movements.*;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.block.BlockLiquid;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.Tuple; import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@@ -79,8 +77,6 @@ public class PathExecutor implements IPathExecutor, Helper {
private PathingBehavior behavior; private PathingBehavior behavior;
private IPlayerContext ctx; private IPlayerContext ctx;
private boolean sprintNextTick;
public PathExecutor(PathingBehavior behavior, IPath path) { public PathExecutor(PathingBehavior behavior, IPath path) {
this.behavior = behavior; this.behavior = behavior;
this.ctx = behavior.ctx; this.ctx = behavior.ctx;
@@ -112,6 +108,7 @@ public class PathExecutor implements IPathExecutor, Helper {
return false; return false;
} }
//System.out.println("Should be at " + whereShouldIBe + " actually am at " + whereAmI);
if (!Blocks.AIR.equals(BlockStateInterface.getBlock(ctx, whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip if (!Blocks.AIR.equals(BlockStateInterface.getBlock(ctx, whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip
for (int i = 0; i < pathPosition - 1 && i < path.length(); i++) {//this happens for example when you lag out and get teleported back a couple blocks for (int i = 0; i < pathPosition - 1 && i < path.length(); i++) {//this happens for example when you lag out and get teleported back a couple blocks
if (whereAmI.equals(path.positions().get(i))) { if (whereAmI.equals(path.positions().get(i))) {
@@ -189,23 +186,22 @@ public class PathExecutor implements IPathExecutor, Helper {
} }
}*/ }*/
//long start = System.nanoTime() / 1000000L; //long start = System.nanoTime() / 1000000L;
BlockStateInterface bsi = new BlockStateInterface(ctx);
for (int i = pathPosition - 10; i < pathPosition + 10; i++) { for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
if (i < 0 || i >= path.movements().size()) { if (i < 0 || i >= path.movements().size()) {
continue; continue;
} }
Movement m = (Movement) path.movements().get(i); IMovement m = path.movements().get(i);
HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak(bsi)); HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak());
HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace(bsi)); HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace());
HashSet<BlockPos> prevWalkInto = new HashSet<>(m.toWalkInto(bsi)); HashSet<BlockPos> prevWalkInto = new HashSet<>(m.toWalkInto());
m.resetBlockCache(); m.resetBlockCache();
if (!prevBreak.equals(new HashSet<>(m.toBreak(bsi)))) { if (!prevBreak.equals(new HashSet<>(m.toBreak()))) {
recalcBP = true; recalcBP = true;
} }
if (!prevPlace.equals(new HashSet<>(m.toPlace(bsi)))) { if (!prevPlace.equals(new HashSet<>(m.toPlace()))) {
recalcBP = true; recalcBP = true;
} }
if (!prevWalkInto.equals(new HashSet<>(m.toWalkInto(bsi)))) { if (!prevWalkInto.equals(new HashSet<>(m.toWalkInto()))) {
recalcBP = true; recalcBP = true;
} }
} }
@@ -214,10 +210,9 @@ public class PathExecutor implements IPathExecutor, Helper {
HashSet<BlockPos> newPlace = new HashSet<>(); HashSet<BlockPos> newPlace = new HashSet<>();
HashSet<BlockPos> newWalkInto = new HashSet<>(); HashSet<BlockPos> newWalkInto = new HashSet<>();
for (int i = pathPosition; i < path.movements().size(); i++) { for (int i = pathPosition; i < path.movements().size(); i++) {
Movement movement = (Movement) path.movements().get(i); newBreak.addAll(path.movements().get(i).toBreak());
newBreak.addAll(movement.toBreak(bsi)); newPlace.addAll(path.movements().get(i).toPlace());
newPlace.addAll(movement.toPlace(bsi)); newWalkInto.addAll(path.movements().get(i).toWalkInto());
newWalkInto.addAll(movement.toWalkInto(bsi));
} }
toBreak = newBreak; toBreak = newBreak;
toPlace = newPlace; toPlace = newPlace;
@@ -271,10 +266,7 @@ public class PathExecutor implements IPathExecutor, Helper {
onTick(); onTick();
return true; return true;
} else { } else {
sprintNextTick = shouldSprintNextTick(); sprintIfRequested();
if (!sprintNextTick) {
ctx.player().setSprinting(false); // letting go of control doesn't make you stop sprinting actually
}
ticksOnCurrent++; ticksOnCurrent++;
if (ticksOnCurrent > currentMovementOriginalCostEstimate + Baritone.settings().movementTimeoutTicks.get()) { if (ticksOnCurrent > currentMovementOriginalCostEstimate + Baritone.settings().movementTimeoutTicks.get()) {
// only cancel if the total time has exceeded the initial estimate // only cancel if the total time has exceeded the initial estimate
@@ -352,41 +344,31 @@ public class PathExecutor implements IPathExecutor, Helper {
/** /**
* Regardless of current path position, snap to the current player feet if possible * Regardless of current path position, snap to the current player feet if possible
*
* @return Whether or not it was possible to snap to the current player feet
*/ */
public boolean snipsnapifpossible() { public boolean snipsnapifpossible() {
if (!ctx.player().onGround && !(ctx.world().getBlockState(ctx.playerFeet()).getBlock() instanceof BlockLiquid)) {
// if we're falling in the air, and not in water, don't splice
return false;
} else {
// we are either onGround or in liquid
if (ctx.player().motionY < -0.1) {
// if we are strictly moving downwards (not stationary)
// we could be falling through water, which could be unsafe to splice
return false; // so don't
}
}
int index = path.positions().indexOf(ctx.playerFeet()); int index = path.positions().indexOf(ctx.playerFeet());
if (index == -1) { if (index == -1) {
return false; return false;
} }
pathPosition = index; // jump directly to current position pathPosition = index;
clearKeys(); clearKeys();
return true; return true;
} }
private boolean shouldSprintNextTick() { private void sprintIfRequested() {
// first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint // first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint
if (!new CalculationContext(behavior.baritone).canSprint) { if (!new CalculationContext(behavior.baritone).canSprint()) {
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false); behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false);
return false; ctx.player().setSprinting(false);
return;
} }
// if the movement requested sprinting, then we're done // if the movement requested sprinting, then we're done
if (behavior.baritone.getInputOverrideHandler().isInputForcedDown(Input.SPRINT)) { if (behavior.baritone.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) {
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false); if (!ctx.player().isSprinting()) {
return true; ctx.player().setSprinting(true);
}
return;
} }
// we'll take it from here, no need for minecraft to see we're holding down control and sprint for us // we'll take it from here, no need for minecraft to see we're holding down control and sprint for us
@@ -394,32 +376,36 @@ public class PathExecutor implements IPathExecutor, Helper {
// however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it // however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it
IMovement current = path.movements().get(pathPosition); IMovement current = path.movements().get(pathPosition);
if (current instanceof MovementDescend) { if (current instanceof MovementDescend && pathPosition < path.length() - 2) {
if (((MovementDescend) current).safeMode()) { if (((MovementDescend) current).safeMode()) {
logDebug("Sprinting would be unsafe"); logDebug("Sprinting would be unsafe");
return false; ctx.player().setSprinting(false);
return;
} }
if (pathPosition < path.length() - 2) { IMovement next = path.movements().get(pathPosition + 1);
IMovement next = path.movements().get(pathPosition + 1); if (next instanceof MovementAscend && current.getDirection().up().equals(next.getDirection().down())) {
if (next instanceof MovementAscend && current.getDirection().up().equals(next.getDirection().down())) { // a descend then an ascend in the same direction
// a descend then an ascend in the same direction if (!ctx.player().isSprinting()) {
pathPosition++; ctx.player().setSprinting(true);
// okay to skip clearKeys and / or onChangeInPathPosition here since this isn't possible to repeat, since it's asymmetric
logDebug("Skipping descend to straight ascend");
return true;
} }
if (canSprintInto(ctx, current, next)) { pathPosition++;
if (ctx.playerFeet().equals(current.getDest())) { // okay to skip clearKeys and / or onChangeInPathPosition here since this isn't possible to repeat, since it's asymmetric
pathPosition++; logDebug("Skipping descend to straight ascend");
onChangeInPathPosition(); return;
onTick();
}
return true;
}
//logDebug("Turning off sprinting " + movement + " " + next + " " + movement.getDirection() + " " + next.getDirection().down() + " " + next.getDirection().down().equals(movement.getDirection()));
} }
if (canSprintInto(ctx, current, next)) {
if (ctx.playerFeet().equals(current.getDest())) {
pathPosition++;
onChangeInPathPosition();
}
if (!ctx.player().isSprinting()) {
ctx.player().setSprinting(true);
}
return;
}
//logDebug("Turning off sprinting " + movement + " " + next + " " + movement.getDirection() + " " + next.getDirection().down() + " " + next.getDirection().down().equals(movement.getDirection()));
} }
if (current instanceof MovementAscend && pathPosition != 0) { if (current instanceof MovementAscend && pathPosition != 0) {
IMovement prev = path.movements().get(pathPosition - 1); IMovement prev = path.movements().get(pathPosition - 1);
@@ -427,11 +413,14 @@ public class PathExecutor implements IPathExecutor, Helper {
BlockPos center = current.getSrc().up(); BlockPos center = current.getSrc().up();
if (ctx.player().posY >= center.getY()) { // playerFeet adds 0.1251 to account for soul sand if (ctx.player().posY >= center.getY()) { // playerFeet adds 0.1251 to account for soul sand
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, false); behavior.baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, false);
return true; if (!ctx.player().isSprinting()) {
ctx.player().setSprinting(true);
}
return;
} }
} }
} }
return false; ctx.player().setSprinting(false);
} }
private static boolean canSprintInto(IPlayerContext ctx, IMovement current, IMovement next) { private static boolean canSprintInto(IPlayerContext ctx, IMovement current, IMovement next) {
@@ -461,7 +450,6 @@ public class PathExecutor implements IPathExecutor, Helper {
failed = true; failed = true;
} }
@Override
public int getPosition() { public int getPosition() {
return pathPosition; return pathPosition;
} }
@@ -527,8 +515,4 @@ public class PathExecutor implements IPathExecutor, Helper {
public Set<BlockPos> toWalkInto() { public Set<BlockPos> toWalkInto() {
return Collections.unmodifiableSet(toWalkInto); return Collections.unmodifiableSet(toWalkInto);
} }
public boolean isSprinting() {
return sprintNextTick;
}
} }
@@ -62,15 +62,13 @@ public class SplicedPath extends PathBase {
return numNodes; return numNodes;
} }
@Override
public int length() {
return path.size();
}
public static Optional<SplicedPath> trySplice(IPath first, IPath second, boolean allowOverlapCutoff) { public static Optional<SplicedPath> trySplice(IPath first, IPath second, boolean allowOverlapCutoff) {
if (second == null || first == null) { if (second == null || first == null) {
return Optional.empty(); return Optional.empty();
} }
if (!Objects.equals(first.getGoal(), second.getGoal())) {
return Optional.empty();
}
if (!first.getDest().equals(second.getSrc())) { if (!first.getDest().equals(second.getSrc())) {
return Optional.empty(); return Optional.empty();
} }
@@ -79,7 +77,6 @@ public class SplicedPath extends PathBase {
for (int i = 0; i < first.length() - 1; i++) { // overlap in the very last element is fine (and required) so only go up to first.length() - 1 for (int i = 0; i < first.length() - 1; i++) { // overlap in the very last element is fine (and required) so only go up to first.length() - 1
if (secondPos.contains(first.positions().get(i))) { if (secondPos.contains(first.positions().get(i))) {
firstPositionInSecond = i; firstPositionInSecond = i;
break;
} }
} }
if (firstPositionInSecond != -1) { if (firstPositionInSecond != -1) {
@@ -97,7 +94,7 @@ public class SplicedPath extends PathBase {
List<IMovement> movements = new ArrayList<>(); List<IMovement> movements = new ArrayList<>();
positions.addAll(first.positions().subList(0, firstPositionInSecond + 1)); positions.addAll(first.positions().subList(0, firstPositionInSecond + 1));
movements.addAll(first.movements().subList(0, firstPositionInSecond)); movements.addAll(first.movements().subList(0, firstPositionInSecond));
positions.addAll(second.positions().subList(positionInSecond + 1, second.length())); positions.addAll(second.positions().subList(positionInSecond + 1, second.length()));
movements.addAll(second.movements().subList(positionInSecond, second.length() - 1)); movements.addAll(second.movements().subList(positionInSecond, second.length() - 1));
return Optional.of(new SplicedPath(positions, movements, first.getNumNodesConsidered() + second.getNumNodesConsidered(), first.getGoal())); return Optional.of(new SplicedPath(positions, movements, first.getNumNodesConsidered() + second.getNumNodesConsidered(), first.getGoal()));
@@ -52,9 +52,7 @@ public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomG
@Override @Override
public void setGoal(Goal goal) { public void setGoal(Goal goal) {
this.goal = goal; this.goal = goal;
if (this.state == State.NONE) { this.state = State.GOAL_SET;
this.state = State.GOAL_SET;
}
} }
@Override @Override
@@ -76,7 +74,7 @@ public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomG
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
switch (this.state) { switch (this.state) {
case GOAL_SET: case GOAL_SET:
if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal() + "", this.goal + "")) { if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal(), this.goal)) {
this.state = State.NONE; this.state = State.NONE;
} }
return new PathingCommand(this.goal, PathingCommandType.CANCEL_AND_SET_GOAL); return new PathingCommand(this.goal, PathingCommandType.CANCEL_AND_SET_GOAL);
@@ -57,6 +57,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
} }
private Goal towards(Entity following) { private Goal towards(Entity following) {
// lol this is trashy but it works
BlockPos pos; BlockPos pos;
if (Baritone.settings().followOffsetDistance.get() == 0) { if (Baritone.settings().followOffsetDistance.get() == 0) {
pos = new BlockPos(following); pos = new BlockPos(following);
@@ -78,7 +79,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
if (entity.equals(ctx.player())) { if (entity.equals(ctx.player())) {
return false; return false;
} }
return ctx.world().loadedEntityList.contains(entity); return ctx.world().loadedEntityList.contains(entity) || ctx.world().playerEntities.contains(entity);
} }
private void scanWorld() { private void scanWorld() {
@@ -21,27 +21,19 @@ import baritone.Baritone;
import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalComposite; import baritone.api.pathing.goals.GoalComposite;
import baritone.api.pathing.goals.GoalGetToBlock; import baritone.api.pathing.goals.GoalGetToBlock;
import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.api.process.IGetToBlockProcess; import baritone.api.process.IGetToBlockProcess;
import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType; import baritone.api.process.PathingCommandType;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.input.Input;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.utils.BaritoneProcessHelper; import baritone.utils.BaritoneProcessHelper;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.ContainerPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess { public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess {
private Block gettingTo; private Block gettingTo;
private List<BlockPos> knownLocations; private List<BlockPos> knownLocations;
@@ -53,8 +45,8 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
@Override @Override
public void getToBlock(Block block) { public void getToBlock(Block block) {
onLostControl();
gettingTo = block; gettingTo = block;
knownLocations = null;
rescan(new ArrayList<>(), new CalculationContext(baritone)); rescan(new ArrayList<>(), new CalculationContext(baritone));
} }
@@ -85,19 +77,12 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get();
if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain
List<BlockPos> current = new ArrayList<>(knownLocations); List<BlockPos> current = new ArrayList<>(knownLocations);
CalculationContext context = new CalculationContext(baritone, true); CalculationContext context = new CalculationContext(baritone);
Baritone.getExecutor().execute(() -> rescan(current, context)); Baritone.getExecutor().execute(() -> rescan(current, context));
} }
Goal goal = new GoalComposite(knownLocations.stream().map(this::createGoal).toArray(Goal[]::new)); Goal goal = new GoalComposite(knownLocations.stream().map(GoalGetToBlock::new).toArray(Goal[]::new));
if (goal.isInGoal(ctx.playerFeet()) && isSafeToCancel) { if (goal.isInGoal(ctx.playerFeet())) {
// we're there onLostControl();
if (rightClickOnArrival(gettingTo)) {
if (rightClick()) {
onLostControl();
}
} else {
onLostControl();
}
} }
return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH);
} }
@@ -106,7 +91,6 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
public void onLostControl() { public void onLostControl() {
gettingTo = null; gettingTo = null;
knownLocations = null; knownLocations = null;
baritone.getInputOverrideHandler().clearAllKeys();
} }
@Override @Override
@@ -117,41 +101,4 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
private void rescan(List<BlockPos> known, CalculationContext context) { private void rescan(List<BlockPos> known, CalculationContext context) {
knownLocations = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known); knownLocations = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known);
} }
}
private Goal createGoal(BlockPos pos) {
return walkIntoInsteadOfAdjacent(gettingTo) ? new GoalTwoBlocks(pos) : new GoalGetToBlock(pos);
}
private boolean rightClick() {
for (BlockPos pos : knownLocations) {
Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
if (reachable.isPresent()) {
baritone.getLookBehavior().updateTarget(reachable.get(), true);
if (knownLocations.contains(ctx.getSelectedBlock().orElse(null))) {
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); // TODO find some way to right click even if we're in an ESC menu
System.out.println(ctx.player().openContainer);
if (!(ctx.player().openContainer instanceof ContainerPlayer)) {
return true;
}
}
return false; // trying to right click, will do it next tick or so
}
}
logDirect("Arrived but failed to right click open");
return true;
}
private boolean walkIntoInsteadOfAdjacent(Block block) {
if (!Baritone.settings().enterPortal.get()) {
return false;
}
return block == Blocks.PORTAL;
}
private boolean rightClickOnArrival(Block block) {
if (!Baritone.settings().rightClickContainerOnArrival.get()) {
return false;
}
return block == Blocks.CRAFTING_TABLE || block == Blocks.FURNACE || block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST;
}
}

Some files were not shown because too many files have changed in this diff Show More