diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 34487ff75..b686a589f 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -11,7 +11,7 @@ Operating system: Java version: Minecraft version: Baritone version: -Forge mods (if used): +Other mods (if used): ## Exception, error or logs Please find your `latest.log` or `debug.log` in this folder and attach it to the issue diff --git a/.github/workflows/gradle_build.yml b/.github/workflows/gradle_build.yml new file mode 100644 index 000000000..34e93bff2 --- /dev/null +++ b/.github/workflows/gradle_build.yml @@ -0,0 +1,39 @@ +# This workflow will build a Java project with Gradle +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + pull_request: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 8 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build + + - name: Archive Artifacts + uses: actions/upload-artifact@v2 + with: + name: Artifacts + path: dist/ + + - name: Archive mapping.txt + uses: actions/upload-artifact@v2 + with: + name: Mappings + path: build/tmp/proguard/mapping.txt diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml new file mode 100644 index 000000000..1af26a476 --- /dev/null +++ b/.github/workflows/run_tests.yml @@ -0,0 +1,26 @@ + +name: Tests + +on: + push: + pull_request: + +jobs: + test: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 9 + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'adopt' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Executing tests + run: ./gradlew test + diff --git a/.gitignore b/.gitignore index 6aeefb22e..97f9d853e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,15 @@ classes/ *.iws /logs/ +# Eclipse Files +.classpath +.project +.settings/ +baritone_Client.launch + # Copyright Files !/.idea/copyright/Baritone.xml !/.idea/copyright/profiles_settings.xml + +.vscode/launch.json + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 75d14ffc2..000000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: java - -sudo: required - -services: -- docker - -install: -- travis_retry docker build -t cabaletta/baritone . - -script: -- docker run --name baritone cabaletta/baritone ./gradlew javadoc -- docker cp baritone:/code/dist dist -- ls dist -- cat dist/checksums.txt - -deploy: - provider: releases - api_key: - secure: YOuiXoJNpB4bW89TQoY2IGXg0tqOKls55YMXsSPU6Mx8WzRu8CjjO/A8KA9nGfNrKM+NucjiKr/h53O2Dp2uyy0i0SLvav/G0MaBMeB1NlPRwFopi6tVPNaoZsvr8NW4BIURhspckYLpOTYWnfmOkIv8q7AxrjUZWPKDlq0dte20UxEqUE6msHJ7U9XlKo/4fX40kvWMfwGI2hTyAtL0cRT1QPsd+uW3OQjAPcQj+jKaWld46V8pBK8g9Qde9mo8HC9NBv97zw1bBF1EFkynW569kElHvaS2Opl2QLGaf66guDbpnqDpGHMhQrDdxsZHJ4RksyITn+8A9UArmbkU35BxKqBeQqOWxod2+M0axdLh1pvX43Q1t9n7RiZBf7GvV8vkXL5Sjf8v6Y4LqkJGhvQkTUwpH+0knwrE761DMCtBC34AiWG70D4u7msmhurkflr9kmRHSj/3lyJ1Q2lkt8L+FOAlQBVs64vXTsfgc6Yge7N0O3UD5hCkrDNoz3BzhNBdCkbdxdKCGip71UZgUNkPy9o3ui8jATNj9ypx3+U8ovqP0XWlJqUZmyeXyNGW9NrLeCkRLTlLnZ/dv6OPONa1oAu4TwF1w5A+TGRFZcZjH/PnZKZDQ1OYQOR6drLKRYdr2unvuf5KUKUGqZ7aYtLGhP0rBvGWddRV7DSmX/s= - all_branches: true - file_glob: true - file: - - dist/* - skip_cleanup: true - on: - tags: true - repo: cabaletta/baritone diff --git a/README.md b/README.md index f709a3d81..7222e4d89 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,71 @@ # Baritone -[![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone/) -[![GitHub All Releases](https://img.shields.io/github/downloads/cabaletta/baritone/total.svg)](https://github.com/cabaletta/baritone/releases/) +

+ GitHub All Releases +

-[![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/) -[![License](https://img.shields.io/badge/license-LGPL--3.0%20with%20anime%20exception-green.svg)](LICENSE) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade) -[![Minecraft](https://img.shields.io/badge/MC-1.12.2-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/master/) -[![Minecraft](https://img.shields.io/badge/MC-1.13.2-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.13.2/) -[![Minecraft](https://img.shields.io/badge/MC-1.14.4-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.14.4/) -[![Minecraft](https://img.shields.io/badge/MC-1.15.2-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.15.2/) -[![Minecraft](https://img.shields.io/badge/MC-1.16.4-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.16.4/) -[![Code of Conduct](https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?style=flat)](https://github.com/cabaletta/baritone/blob/master/CODE_OF_CONDUCT.md) -[![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/) -[![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) -![Lines of Code](https://tokei.rs/b1/github/cabaletta/baritone?category=code) -[![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/) -[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.2.14%20/%20v1.3.8%20/%20v1.4.6%20/%20v1.5.3-brightgreen.svg)](https://impactclient.net/) -[![KAMI Blue integration](https://img.shields.io/badge/KAMI%20Blue%20integration-v1.2.14--master-green)](https://github.com/kami-blue/client) -[![ForgeHax integration](https://img.shields.io/badge/ForgeHax%20%22integration%22-scuffed-yellow.svg)](https://github.com/fr1kin/ForgeHax/) -[![Aristois add-on integration](https://img.shields.io/badge/Aristois%20add--on%20integration-v1.3.4%20/%20v1.4.1-green.svg)](https://gitlab.com/emc-mods-indrit/baritone_api) -[![rootNET integration](https://img.shields.io/badge/rootNET%20integration-v1.2.14-green.svg)](https://rootnet.dev/) -[![Future integration](https://img.shields.io/badge/Future%20integration-v1.2.12%20%2F%20v1.3.6%20%2F%20v1.4.4-red)](https://futureclient.net/) -[![RusherHack integration](https://img.shields.io/badge/RusherHack%20integration-v1.2.14-green)](https://rusherhack.org/) -[![forthebadge](https://forthebadge.com/images/badges/built-with-swag.svg)](http://forthebadge.com/) -[![forthebadge](https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg)](http://forthebadge.com/) +

+ Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft + Minecraft +

-A Minecraft pathfinder bot. +

+ Build Status + Release + License + Codacy Badge + Code of Conduct + Known Vulnerabilities + Contributions welcome + Issues + GitHub issues-closed + Pull Requests + GitHub contributors + GitHub commits + Code size + GitHub repo size + Lines of Code +

-Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#0730 on Baritone which I recommend. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do. [Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa) +

+ Impact integration + KAMI Blue integration + ForgeHax integration + Aristois add-on integration + rootNET integration + Future integration + RusherHack integration +

-The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.2.14/baritone-api-forge-1.2.14.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. +

+ forthebadge + forthebadge +

+ +A Minecraft pathfinder bot. + +[**Baritone Discord Server**](http://discord.gg/s6fRBAUpmr) + +Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#0730 on Baritone which I recommend. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do. + +[Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa) + +The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.2.15/baritone-api-forge-1.2.15.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. For 1.15.2, [click here](https://www.youtube.com/watch?v=j1qKtCZFURM) and see description. If you need Forge 1.15.2, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.5.3), follow the instructions, and get the `api-forge` jar. -For 1.16.4, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge 1.16.4, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.2) and get the `api-forge` jar. +For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge or Fabric 1.16.5, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.3) and get the `api-forge` or `api-fabric` jar. **For 1.16.5 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.6.3/baritone-api-fabric-1.6.3.jar)**. + +If you need Forge or Fabric 1.17.1, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.7.2) and get the `api-forge` or `api-fabric` jar. **For 1.17.1 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.7.2/baritone-api-fabric-1.7.2.jar)**. + +If you need Forge or Fabric 1.18.1, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.8.2) and get the `api-forge` or `api-fabric` jar. **For 1.18.1 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.8.2/baritone-api-fabric-1.8.2.jar)**. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), -the original version of the bot for Minecraft 1.8.9, rebuilt for 1.12.2 through 1.16.4. 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.9, rebuilt for 1.12.2 onwards. 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). Have committed at least once a day from Aug 1, 2018, to Aug 1, 2019. @@ -75,7 +97,7 @@ jar. Below is an example of basic usage for changing some settings, and then pathing to an X/Z goal. -``` +```java BaritoneAPI.getSettings().allowSprint.value = true; BaritoneAPI.getSettings().primaryTimeoutMS.value = 2000L; diff --git a/SETUP.md b/SETUP.md index e7ef6c274..57866b192 100644 --- a/SETUP.md +++ b/SETUP.md @@ -2,7 +2,7 @@ The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. -You can also use a custom version json for Minecraft, with the [1.14.4](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1) version or the [1.15.2](https://www.dropbox.com/s/8rx6f0kts9hvd4f/1.15.2-Baritone.zip?dl=1) version +You can also use a custom version json for Minecraft, with the [1.14.4](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1) version or the [1.15.2](https://www.dropbox.com/s/8rx6f0kts9hvd4f/1.15.2-Baritone.zip?dl=1) version or the [1.16.5](https://www.dropbox.com/s/i6f292o2i7o9acp/1.16.5-Baritone.zip?dl=1) version. Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. @@ -11,9 +11,9 @@ These releases are not always completely up to date with latest features, and ar Link to the releases page: [Releases](https://github.com/cabaletta/baritone/releases) -v1.2.* is for 1.12.2, v1.3.* is for 1.13.2 +v1.2.* is for 1.12.2, v1.3.* is for 1.13.2, v1.4.* is for 1.14.4, v1.5.* is for 1.15.2, v1.6.* is for 1.16.5, v1.7.* is for 1.17.1, v1.8.* is for 1.18.1 -Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`. +Any official release will be GPG signed by leijurv (44A3EA646EADAC6A). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by that public keys of `checksums.txt`. The build is fully deterministic and reproducible, and you can verify Travis did it properly by running `docker build --no-cache -t cabaletta/baritone .` 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). @@ -22,20 +22,16 @@ The build is fully deterministic and reproducible, and you can verify Travis did Building Baritone will result in 5 artifacts created in the ``dist`` directory. These are the same as the artifacts created in the [releases](https://github.com/cabaletta/baritone/releases). -**The Forge release can simply be added as a Forge mod.** +**The Forge and Fabric releases can simply be added as a Forge/Fabric mods.** If another one of your Forge mods has a Baritone integration, you want `baritone-api-forge-VERSION.jar`. Otherwise, you want `baritone-standalone-forge-VERSION.jar` - **API**: Only the non-api packages are obfuscated. This should be used in environments where other mods would like to use Baritone's features. -- **Forge API**: Same as API, but packaged for Forge. This should be used where another mod has a Baritone integration. +- **Forge/Fabric API**: Same as API, but packaged for Forge/Fabric. This should be used where another mod has a Baritone integration. - **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. -- **Forge Standalone**: Same as Standalone, but packaged for Forge. This should be used when Baritone is your only Forge mod, or none of your other Forge mods integrate with Baritone. +- **Forge/Fabric Standalone**: Same as Standalone, but packaged for Forge/Fabric. This should be used when Baritone is your only Forge/Fabric mod, or none of your other Forge/Fabric mods integrate with Baritone. - **Unoptimized**: Nothing is obfuscated. This shouldn't be used ever in production. - -## More Info -To replace out Impact 4.5's Baritone build with a customized one, build Baritone as above then copy & **rename** `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.2/baritone-api-1.2.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.5/1.12.2-Impact_4.5.json`, find the line `"name": "cabaletta:baritone-api:1.2"`, remove the comma from the end, and **entirely remove the NEXT line** (starts with `"url"`). **Restart your launcher** then load as normal. - -You can verify whether or not it worked by running `.b version` in chat (only valid in Impact). It should print out the version that you downloaded. Note: The version that comes with 4.5 is `v1.2.3`. +- **Forge/Fabric Unoptimized**: Same as Unoptimized, but packaged for Forge/Fabric. ## Build it yourself - Clone or download Baritone @@ -47,13 +43,13 @@ You can verify whether or not it worked by running `.b version` in chat (only va ## Command Line On Mac OSX and Linux, use `./gradlew` instead of `gradlew`. -If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8. +If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16 for 1.17.1, and JDK 17 for 1.18.1. To check which java you are using do `java -version` in a command prompt or terminal. -If you are using anything above OpenJDK 8, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes. +If you are using anything above OpenJDK 8 for 1.12.2-1.16.5, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes. -Open JDK 8 download: https://openjdk.java.net/install/ +Open JDK download: https://openjdk.java.net/install/ #### macOS guide In order to get JDK 8, Try running the following command: `% /usr/libexec/java_home -V` @@ -89,6 +85,12 @@ For minecraft 1.15.2+, run the following instead to include the Forge jars: $ gradlew build -Pbaritone.forge_build ``` +Do this instead for Fabric jars: + +``` +$ gradlew build -Pbaritone.fabric_build +``` + Running Baritone: ``` diff --git a/USAGE.md b/USAGE.md index 35aa90a7b..46241e3fe 100644 --- a/USAGE.md +++ b/USAGE.md @@ -32,13 +32,13 @@ Watch this [showcase video](https://youtu.be/CZkLXWo4Fg4)! To toggle a boolean setting, just say its name in chat (for example saying `allowBreak` toggles whether Baritone will consider breaking blocks). For a numeric setting, say its name then the new value (like `primaryTimeoutMS 250`). It's case insensitive. To reset a setting to its default value, say `acceptableThrowawayItems reset`. To reset all settings, say `reset`. To see all settings that have been modified from their default values, say `modified`. -Some common examples: +Commands in Baritone: - `thisway 1000` then `path` to go in the direction you're facing for a thousand blocks - `goal x y z` or `goal x z` or `goal y`, then `path` to set a goal to a certain coordinate then path to it - `goto x y z` or `goto x z` or `goto y` to go to a certain coordinate (in a single step, starts going immediately) - `goal` to set the goal to your player's feet - `goal clear` to clear the goal -- `cancel` or `stop` to stop everything +- `cancel` or `stop` to stop everything, `forcecancel` is also an option - `goto portal` or `goto ender_chest` or `goto block_type` to go to a block. (in Impact, `.goto` is an alias for `.b goto` for the most part) - `mine diamond_ore iron_ore` to mine diamond ore or iron ore (turn on the setting `legitMine` to only mine ores that it can actually see. It will explore randomly around y=11 until it finds them.) An amount of blocks can also be specified, for example, `mine 64 diamond_ore`. - `click` to click your destination on the screen. Right click path to on top of the block, left click to path into it (either at foot level or eye level), and left click and drag to select an area (`#help sel` to see what you can do with that selection). @@ -47,15 +47,23 @@ Some common examples: - `build` to build a schematic. `build blah.schematic` will load `schematics/blah.schematic` and build it with the origin being your player feet. `build blah.schematic x y z` to set the origin. Any of those can be relative to your player (`~ 69 ~-420` would build at x=player x, y=69, z=player z-420). - `schematica` to build the schematic that is currently open in schematica - `tunnel` to dig and make a tunnel, 1x2. It will only deviate from the straight line if necessary such as to avoid lava. For a dumber tunnel that is really just cleararea, you can `tunnel 3 2 100`, to clear an area 3 high, 2 wide, and 100 deep. -- `farm` to automatically harvest, replant, or bone meal crops +- `farm` to automatically harvest, replant, or bone meal crops. Use `farm ` or `farm ` to limit the max distance from the starting point or a waypoint. - `axis` to go to an axis or diagonal axis at y=120 (`axisHeight` is a configurable setting, defaults to 120). - `explore x z` to explore the world from the origin of x,z. Leave out x and z to default to player feet. This will continually path towards the closest chunk to the origin that it's never seen before. `explorefilter filter.json` with optional invert can be used to load in a list of chunks to load. - `invert` to invert the current goal and path. This gets as far away from it as possible, instead of as close as possible. For example, do `goal` then `invert` to run as far as possible from where you're standing at the start. +- `come` tells Baritone to head towards your camera, useful when freecam doesn't move your player position. +- `blacklist` will stop baritone from going to the closest block so it won't attempt to get to it. +- `eta` to get information about the estimated time until the next segment and the goal, be aware that the ETA to your goal is really unprecise. +- `proc` to view miscellaneous information about the process currently controlling Baritone. +- `repack` to re-cache the chunks around you. +- `gc` to call `System.gc()` which may free up some memory. +- `render` to fix glitched chunk rendering without having to reload all of them. +- `reloadall` to reload Baritone's world cache or `saveall` to save Baritone's world cache. +- `find` to search through Baritone's cache and attempt to find the location of the block. +- `surface` or `top` to tell Baritone to head towards the closest surface-like area, this can be the surface or highest available air space. - `version` to get the version of Baritone you're running - `damn` daniel -For the rest of the commands, you can take a look at the code [here](https://baritone.leijurv.com/baritone/api/Settings.html). - All the settings and documentation are here. If you find HTML easier to read than Javadoc, you can look here. There are about a hundred settings, but here are some fun / interesting / important ones that you might want to look at changing in normal usage of Baritone. The documentation for each can be found at the above links. diff --git a/build.gradle b/build.gradle index 002737242..913a66920 100755 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ import baritone.gradle.task.ProguardTask import org.apache.tools.ant.taskdefs.condition.Os apply plugin: 'java' +apply plugin: 'maven' apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' @@ -199,3 +200,25 @@ task proguard(type: ProguardTask) { task createDist(type: CreateDistTask, dependsOn: proguard) build.finalizedBy(createDist) + +install { + def jarApiName = String.format("%s-api-%s", rootProject.name, version.toString()) + def jarApiForgeName = String.format("%s-api-forge-%s", rootProject.name, version.toString()) + def jarSAName = String.format("%s-standalone-%s", rootProject.name, version.toString()) + def jarSAForgeName = String.format("%s-standalone-forge-%s", rootProject.name, version.toString()) + + artifacts { + archives file("$buildDir/libs/"+jarApiName+".jar") + archives file("$buildDir/libs/"+jarApiForgeName+".jar") + archives file("$buildDir/libs/"+jarSAName+".jar") + archives file("$buildDir/libs/"+jarSAForgeName+".jar") + } + repositories.mavenInstaller { + addFilter('api') { artifact, file -> artifact.name == "baritone-api" } + addFilter('api-forge') { artifact, file -> artifact.name == "baritone-api-forge" } + addFilter('standalone') { artifact, file -> artifact.name == "baritone-standalone" } + addFilter('standalone-forge') { artifact, file -> artifact.name == "baritone-standalone-forge" } + } +} + +install.dependsOn(build) diff --git a/scripts/proguard.pro b/scripts/proguard.pro index b1856e6c8..b20bebba5 100644 --- a/scripts/proguard.pro +++ b/scripts/proguard.pro @@ -24,6 +24,7 @@ -keep class baritone.api.IBaritoneProvider -keep class baritone.api.utils.MyChunkPos { *; } # even in standalone we need to keep this for gson reflect +-keepname class baritone.api.utils.BlockOptionalMeta # this name is exposed to the user, so we need to keep it in all builds # Keep any class or member annotated with @KeepName so we dont have to put everything in the script -keep,allowobfuscation @interface baritone.KeepName @@ -45,7 +46,6 @@ #proguard doesnt like it when it cant find our fake schematica classes -dontwarn baritone.utils.schematic.schematica.** - # Keep - Applications. Keep all application classes, along with their 'main' # methods. -keepclasseswithmembers public class * { @@ -334,3 +334,5 @@ public java.lang.String substring(int); public java.lang.String substring(int,int); } + +-printmapping mapping.txt diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 2fb7825cc..5bdfedf65 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -17,8 +17,10 @@ package baritone.api; +import baritone.api.utils.NotificationHelper; import baritone.api.utils.SettingsUtil; import baritone.api.utils.TypeUtils; +import baritone.api.utils.gui.BaritoneToast; import net.minecraft.block.Block; import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; @@ -33,6 +35,7 @@ import java.lang.reflect.Type; import java.util.List; import java.util.*; import java.util.function.Consumer; +import java.util.function.BiConsumer; /** * Baritone's settings. Settings apply to all Baritone instances. @@ -70,9 +73,9 @@ public final class Settings { public final Setting assumeExternalAutoTool = new Setting<>(false); /** - * If this setting is on, no auto tool will occur at all, not at calculation time nor execution time + * Automatically select the best available tool */ - public final Setting disableAutoTool = new Setting<>(false); + public final Setting autoTool = new Setting<>(true); /** * It doesn't actually take twenty ticks to place a block, this cost is so high @@ -187,6 +190,13 @@ public final class Settings { /** * Blocks that Baritone is not allowed to break */ + public final Setting> blocksToDisallowBreaking = new Setting<>(new ArrayList<>( + // Leave Empty by Default + )); + + /** + * blocks that baritone shouldn't break, but can if it needs to. + */ public final Setting> blocksToAvoidBreaking = new Setting<>(new ArrayList<>(Arrays.asList( // TODO can this be a HashSet or ImmutableSet? Blocks.CRAFTING_TABLE, Blocks.FURNACE, @@ -194,6 +204,11 @@ public final class Settings { Blocks.TRAPPED_CHEST ))); + /** + * this multiplies the break speed, if set above 1 it's "encourage breaking" instead + */ + public final Setting avoidBreakingMultiplier = new Setting<>(.1); + /** * A list of blocks to be treated as if they're air. *

@@ -203,6 +218,29 @@ public final class Settings { ))); + /** + * A list of blocks to be treated as correct. + *

+ * If a schematic asks for any block on this list at a certain position, it will be treated as correct, regardless of what it currently is. + */ + public final Setting> buildSkipBlocks = new Setting<>(new ArrayList<>(Arrays.asList( + + ))); + + /** + * A mapping of blocks to blocks treated as correct in their position + *

+ * If a schematic asks for a block on this mapping, all blocks on the mapped list will be accepted at that location as well + */ + public final Setting>> buildValidSubstitutes = new Setting<>(new HashMap<>()); + + /** + * A mapping of blocks to blocks to be built instead + *

+ * If a schematic asks for a block on this mapping, Baritone will place the first placeable block in the mapped list + */ + public final Setting>> buildSubstitutes = new Setting<>(new HashMap<>()); + /** * A list of blocks to become air *

@@ -217,6 +255,11 @@ public final class Settings { */ public final Setting buildIgnoreExisting = new Setting<>(false); + /** + * If this is true, the builder will ignore directionality of certain blocks like glazed terracotta. + */ + public final Setting buildIgnoreDirection = new Setting<>(false); + /** * If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block. *

@@ -344,6 +387,9 @@ public final class Settings { */ public final Setting mobSpawnerAvoidanceCoefficient = new Setting<>(2.0); + /** + * Distance to avoid mob spawners. + */ public final Setting mobSpawnerAvoidanceRadius = new Setting<>(16); /** @@ -353,6 +399,9 @@ public final class Settings { */ public final Setting mobAvoidanceCoefficient = new Setting<>(1.5); + /** + * Distance to avoid mobs. + */ public final Setting mobAvoidanceRadius = new Setting<>(8); /** @@ -519,13 +568,6 @@ public final class Settings { */ public final Setting pruneRegionsFromRAM = new Setting<>(true); - /** - * Remember the contents of containers (chests, echests, furnaces) - *

- * Really buggy since the packet stuff is multithreaded badly thanks to brady - */ - public final Setting containerMemory = new Setting<>(false); - /** * Fill in blocks behind you */ @@ -574,6 +616,12 @@ public final class Settings { */ public final Setting renderGoal = new Setting<>(true); + /** + * Render the goal as a sick animated thingy instead of just a box + * (also controls animation of GoalXZ if {@link #renderGoalXZBeacon} is enabled) + */ + public final Setting renderGoalAnimated = new Setting<>(true); + /** * Render selection boxes */ @@ -643,7 +691,7 @@ public final class Settings { /** * When GetToBlockProcess or MineProcess fails to calculate a path, instead of just giving up, mark the closest instance - * of that block as "unreachable" and go towards the next closest. GetToBlock expands this seaarch to the whole "vein"; MineProcess does not. + * of that block as "unreachable" and go towards the next closest. GetToBlock expands this search to the whole "vein"; MineProcess does not. * This is because MineProcess finds individual impossible blocks (like one block in a vein that has gravel on top then lava, so it can't break) * Whereas GetToBlock should blacklist the whole "vein" if it can't get to any of them. */ @@ -698,6 +746,16 @@ public final class Settings { */ public final Setting censorRanCommands = new Setting<>(false); + /** + * Stop using tools just before they are going to break. + */ + public final Setting itemSaver = new Setting<>(false); + + /** + * Durability to leave on the tool when using itemSaver + */ + public final Setting itemSaverThreshold = new Setting<>(10); + /** * Always prefer silk touch tools over regular tools. This will not sacrifice speed, but it will always prefer silk * touch tools over other tools of the same speed. This includes always choosing ANY silk touch tool over your hand. @@ -758,7 +816,7 @@ public final class Settings { public final Setting allowOnlyExposedOresDistance = new Setting<>(1); /** - * When GetToBlock doesn't know any locations for the desired block, explore randomly instead of giving up. + * When GetToBlock or non-legit Mine doesn't know any locations for the desired block, explore randomly instead of giving up. */ public final Setting exploreForBlocks = new Setting<>(true); @@ -810,6 +868,11 @@ public final class Settings { */ public final Setting layerOrder = new Setting<>(false); + /** + * How high should the individual layers be? + */ + public final Setting layerHeight = new Setting<>(1); + /** * Start building the schematic at a specific layer. * Can help on larger builds when schematic wants to break things its already built @@ -821,6 +884,11 @@ public final class Settings { */ public final Setting skipFailedLayers = new Setting<>(false); + /** + * Only build the selected part of schematics + */ + public final Setting buildOnlySelection = new Setting<>(false); + /** * How far to move before repeating the build. 0 to disable repeating on a certain axis, 0,0,0 to disable entirely */ @@ -831,6 +899,13 @@ public final class Settings { */ public final Setting buildRepeatCount = new Setting<>(-1); + /** + * Don't notify schematics that they are moved. + * e.g. replacing will replace the same spots for every repetition + * Mainly for backward compatibility. + */ + public final Setting buildRepeatSneaky = new Setting<>(true); + /** * Allow standing above a block while mining it, in BuilderProcess *

@@ -939,6 +1014,7 @@ public final class Settings { * Disallow MineBehavior from using X-Ray to see where the ores are. Turn this option on to force it to mine "legit" * where it will only mine an ore once it can actually see it, so it won't do or know anything that a normal player * couldn't. If you don't want it to look like you're X-Raying, turn this on + * This will always explore, regardless of exploreForBlocks */ public final Setting legitMine = new Setting<>(false); @@ -1025,6 +1101,20 @@ public final class Settings { */ public final Setting> logger = new Setting<>(Minecraft.getInstance().ingameGUI.getChatGUI()::printChatMessage); + /** + * The function that is called when Baritone will send a desktop notification. This function can be added to + * via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting + * {@link Setting#value}; + */ + public final Setting> notifier = new Setting<>(NotificationHelper::notify); + + /** + * The function that is called when Baritone will show a toast. This function can be added to + * via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting + * {@link Setting#value}; + */ + public final Setting> toaster = new Setting<>(BaritoneToast::addOrUpdate); + /** * The size of the box that is rendered when the current goal is a GoalYLevel */ @@ -1115,6 +1205,11 @@ public final class Settings { */ public final Setting renderSelectionCorners = new Setting<>(true); + /** + * Use sword to mine. + */ + public final Setting useSwordToMine = new Setting<>(true); + /** * Desktop notifications */ diff --git a/src/api/java/baritone/api/behavior/IPathingBehavior.java b/src/api/java/baritone/api/behavior/IPathingBehavior.java index 5444bb838..83db7ab3a 100644 --- a/src/api/java/baritone/api/behavior/IPathingBehavior.java +++ b/src/api/java/baritone/api/behavior/IPathingBehavior.java @@ -58,6 +58,15 @@ public interface IPathingBehavior extends IBehavior { return Optional.of(current.getPath().ticksRemainingFrom(start)); } + /** + * Returns the estimated remaining ticks to the current goal. + * Given that the return type is an optional, {@link Optional#empty()} + * will be returned in the case that there is no current goal. + * + * @return The estimated remaining ticks to the current goal. + */ + Optional estimatedTicksToGoal(); + /** * @return The current pathing goal */ diff --git a/src/api/java/baritone/api/cache/IContainerMemory.java b/src/api/java/baritone/api/cache/IContainerMemory.java deleted file mode 100644 index 5c19d43b9..000000000 --- a/src/api/java/baritone/api/cache/IContainerMemory.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.api.cache; - -import net.minecraft.util.math.BlockPos; - -import java.util.Map; - -/** - * @author Brady - * @since 9/23/2018 - */ -public interface IContainerMemory { - - /** - * Gets a remembered inventory by its block position. - * - * @param pos The position of the container block - * @return The remembered inventory - */ - IRememberedInventory getInventoryByPos(BlockPos pos); - - /** - * Gets the map of all block positions to their remembered inventories. - * - * @return Map of block positions to their respective remembered inventories - */ - Map getRememberedInventories(); -} diff --git a/src/api/java/baritone/api/cache/IRememberedInventory.java b/src/api/java/baritone/api/cache/IRememberedInventory.java deleted file mode 100644 index a7890fe3a..000000000 --- a/src/api/java/baritone/api/cache/IRememberedInventory.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.api.cache; - -import net.minecraft.item.ItemStack; - -import java.util.List; - -/** - * @author Brady - * @since 9/23/2018 - */ -public interface IRememberedInventory { - - /** - * @return The contents of this inventory - */ - List getContents(); - - /** - * @return The number of slots in this inventory - */ - int getSize(); -} diff --git a/src/api/java/baritone/api/cache/IWorldData.java b/src/api/java/baritone/api/cache/IWorldData.java index 1eaade4c0..200771935 100644 --- a/src/api/java/baritone/api/cache/IWorldData.java +++ b/src/api/java/baritone/api/cache/IWorldData.java @@ -37,9 +37,4 @@ public interface IWorldData { */ IWaypointCollection getWaypoints(); - /** - * @return The {@link IContainerMemory} instance - * @see IContainerMemory - */ - IContainerMemory getContainerMemory(); } diff --git a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java index 54ae9e8c4..e438da308 100644 --- a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java +++ b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java @@ -253,8 +253,8 @@ public class TabCompleteHelper { public TabCompleteHelper addSettings() { return append( BaritoneAPI.getSettings().allSettings.stream() + .filter(s -> !SettingsUtil.javaOnlySetting(s)) .map(Settings.Setting::getName) - .filter(s -> !s.equalsIgnoreCase("logger")) .sorted(String.CASE_INSENSITIVE_ORDER) ); } diff --git a/src/api/java/baritone/api/pathing/goals/Goal.java b/src/api/java/baritone/api/pathing/goals/Goal.java index acee68db8..95462f961 100644 --- a/src/api/java/baritone/api/pathing/goals/Goal.java +++ b/src/api/java/baritone/api/pathing/goals/Goal.java @@ -54,4 +54,18 @@ public interface Goal { default double heuristic(BlockPos pos) { return heuristic(pos.getX(), pos.getY(), pos.getZ()); } + + /** + * Returns the heuristic at the goal. + * i.e. {@code heuristic() == heuristic(x,y,z)} + * when {@code isInGoal(x,y,z) == true} + * This is needed by {@code PathingBehavior#estimatedTicksToGoal} because + * some Goals actually do not have a heuristic of 0 when that condition is met + * + * @return The estimate number of ticks to satisfy the goal when the goal + * is already satisfied + */ + default double heuristic() { + return 0; + } } diff --git a/src/api/java/baritone/api/pathing/goals/GoalBlock.java b/src/api/java/baritone/api/pathing/goals/GoalBlock.java index c85e5cadd..bd339549b 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalBlock.java +++ b/src/api/java/baritone/api/pathing/goals/GoalBlock.java @@ -87,9 +87,9 @@ public class GoalBlock implements Goal, IGoalRenderPos { public static double calculate(double xDiff, int yDiff, double zDiff) { double heuristic = 0; - // if yDiff is 1 that means that pos.getY()-this.y==1 which means that we're 1 block below where we should be - // therefore going from 0,0,0 to a GoalYLevel of pos.getY()-this.y is accurate - heuristic += GoalYLevel.calculate(yDiff, 0); + // if yDiff is 1 that means that currentY-goalY==1 which means that we're 1 block above where we should be + // therefore going from 0,yDiff,0 to a GoalYLevel of 0 is accurate + heuristic += GoalYLevel.calculate(0, yDiff); //use the pythagorean and manhattan mixture from GoalXZ heuristic += GoalXZ.calculate(xDiff, zDiff); diff --git a/src/api/java/baritone/api/pathing/goals/GoalComposite.java b/src/api/java/baritone/api/pathing/goals/GoalComposite.java index 415f74e56..47522492b 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalComposite.java +++ b/src/api/java/baritone/api/pathing/goals/GoalComposite.java @@ -57,6 +57,16 @@ public class GoalComposite implements Goal { return min; } + @Override + public double heuristic() { + double min = Double.MAX_VALUE; + for (Goal g : goals) { + // just take the highest value that is guaranteed to be inside the goal + min = Math.min(min, g.heuristic()); + } + return min; + } + @Override public String toString() { return "GoalComposite" + Arrays.toString(goals); diff --git a/src/api/java/baritone/api/pathing/goals/GoalInverted.java b/src/api/java/baritone/api/pathing/goals/GoalInverted.java index 197369241..354e2ce39 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalInverted.java +++ b/src/api/java/baritone/api/pathing/goals/GoalInverted.java @@ -45,6 +45,11 @@ public class GoalInverted implements Goal { return -origin.heuristic(x, y, z); } + @Override + public double heuristic() { + return Double.NEGATIVE_INFINITY; + } + @Override public String toString() { return String.format("GoalInverted{%s}", origin.toString()); diff --git a/src/api/java/baritone/api/pathing/goals/GoalNear.java b/src/api/java/baritone/api/pathing/goals/GoalNear.java index 73d64ed9f..6a8226fb4 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalNear.java +++ b/src/api/java/baritone/api/pathing/goals/GoalNear.java @@ -19,6 +19,8 @@ package baritone.api.pathing.goals; import baritone.api.utils.SettingsUtil; import baritone.api.utils.interfaces.IGoalRenderPos; +import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; +import it.unimi.dsi.fastutil.doubles.DoubleIterator; import net.minecraft.util.math.BlockPos; public class GoalNear implements Goal, IGoalRenderPos { @@ -51,6 +53,34 @@ public class GoalNear implements Goal, IGoalRenderPos { return GoalBlock.calculate(xDiff, yDiff, zDiff); } + @Override + public double heuristic() {// TODO less hacky solution + int range = (int) Math.ceil(Math.sqrt(rangeSq)); + DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978 + double minOutside = Double.POSITIVE_INFINITY; + for (int dx = -range; dx <= range; dx++) { + for (int dy = -range; dy <= range; dy++) { + for (int dz = -range; dz <= range; dz++) { + double h = heuristic(x + dx, y + dy, z + dz); + if (h < minOutside && isInGoal(x + dx, y + dy, z + dz)) { + maybeAlwaysInside.add(h); + } else { + minOutside = Math.min(minOutside, h); + } + } + } + } + double maxInside = Double.NEGATIVE_INFINITY; + DoubleIterator it = maybeAlwaysInside.iterator(); + while (it.hasNext()) { + double inside = it.nextDouble(); + if (inside < minOutside) { + maxInside = Math.max(maxInside, inside); + } + } + return maxInside; + } + @Override public BlockPos getGoalPos() { return new BlockPos(x, y, z); diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java index 287e3e9ed..503ae7f43 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -18,6 +18,8 @@ package baritone.api.pathing.goals; import baritone.api.utils.SettingsUtil; +import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; +import it.unimi.dsi.fastutil.doubles.DoubleIterator; import net.minecraft.util.math.BlockPos; import java.util.Arrays; @@ -65,7 +67,7 @@ public class GoalRunAway implements Goal { } @Override - public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock + public double heuristic(int x, int y, int z) {// mostly copied from GoalBlock double min = Double.MAX_VALUE; for (BlockPos p : from) { double h = GoalXZ.calculate(p.getX() - x, p.getZ() - z); @@ -80,6 +82,48 @@ public class GoalRunAway implements Goal { return min; } + @Override + public double heuristic() {// TODO less hacky solution + int distance = (int) Math.ceil(Math.sqrt(distanceSq)); + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int minZ = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + int maxZ = Integer.MIN_VALUE; + for (BlockPos p : from) { + minX = Math.min(minX, p.getX() - distance); + minY = Math.min(minY, p.getY() - distance); + minZ = Math.min(minZ, p.getZ() - distance); + maxX = Math.max(minX, p.getX() + distance); + maxY = Math.max(minY, p.getY() + distance); + maxZ = Math.max(minZ, p.getZ() + distance); + } + DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978 + double minOutside = Double.POSITIVE_INFINITY; + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + double h = heuristic(x, y, z); + if (h < minOutside && isInGoal(x, y, z)) { + maybeAlwaysInside.add(h); + } else { + minOutside = Math.min(minOutside, h); + } + } + } + } + double maxInside = Double.NEGATIVE_INFINITY; + DoubleIterator it = maybeAlwaysInside.iterator(); + while (it.hasNext()) { + double inside = it.nextDouble(); + if (inside < minOutside) { + maxInside = Math.max(maxInside, inside); + } + } + return maxInside; + } + @Override public String toString() { if (maintainY != null) { diff --git a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java index 1f8e837a5..cd9fef200 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java +++ b/src/api/java/baritone/api/pathing/goals/GoalStrictDirection.java @@ -64,6 +64,11 @@ public class GoalStrictDirection implements Goal { return heuristic; } + @Override + public double heuristic() { + return Double.NEGATIVE_INFINITY; + } + @Override public String toString() { return String.format( diff --git a/src/api/java/baritone/api/schematic/CompositeSchematic.java b/src/api/java/baritone/api/schematic/CompositeSchematic.java index 22df6a4ee..17c1150a8 100644 --- a/src/api/java/baritone/api/schematic/CompositeSchematic.java +++ b/src/api/java/baritone/api/schematic/CompositeSchematic.java @@ -71,4 +71,11 @@ public class CompositeSchematic extends AbstractSchematic { } return entry.schematic.desiredState(x - entry.x, y - entry.y, z - entry.z, current, approxPlaceable); } + + @Override + public void reset() { + for (CompositeSchematicEntry entry : schematicArr) { + entry.schematic.reset(); + } + } } diff --git a/src/api/java/baritone/api/schematic/FillSchematic.java b/src/api/java/baritone/api/schematic/FillSchematic.java index e43ddb93c..5936b8977 100644 --- a/src/api/java/baritone/api/schematic/FillSchematic.java +++ b/src/api/java/baritone/api/schematic/FillSchematic.java @@ -19,7 +19,6 @@ package baritone.api.schematic; import baritone.api.utils.BlockOptionalMeta; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; import java.util.List; @@ -44,8 +43,6 @@ public class FillSchematic extends AbstractSchematic { public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { if (bom.matches(current)) { return current; - } else if (current.getBlock() != Blocks.AIR) { - return Blocks.AIR.getDefaultState(); } for (BlockState placeable : approxPlaceable) { if (bom.matches(placeable)) { diff --git a/src/api/java/baritone/api/schematic/ISchematic.java b/src/api/java/baritone/api/schematic/ISchematic.java index 88ce4cf7d..592b5e84d 100644 --- a/src/api/java/baritone/api/schematic/ISchematic.java +++ b/src/api/java/baritone/api/schematic/ISchematic.java @@ -73,6 +73,11 @@ public interface ISchematic { */ BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable); + /** + * Resets possible caches to avoid wrong behavior when moving the schematic around + */ + default void reset() {} + /** * @return The width (X axis length) of this schematic */ diff --git a/src/api/java/baritone/api/schematic/ReplaceSchematic.java b/src/api/java/baritone/api/schematic/ReplaceSchematic.java index 3e102cbba..1b1c4d4e7 100644 --- a/src/api/java/baritone/api/schematic/ReplaceSchematic.java +++ b/src/api/java/baritone/api/schematic/ReplaceSchematic.java @@ -31,6 +31,18 @@ public class ReplaceSchematic extends MaskSchematic { this.cache = new Boolean[widthX()][heightY()][lengthZ()]; } + @Override + public void reset() { + // it's final, can't use this.cache = new Boolean[widthX()][heightY()][lengthZ()] + for (int x = 0; x < cache.length; x++) { + for (int y = 0; y < cache[0].length; y++) { + for (int z = 0; z < cache[0][0].length; z++) { + cache[x][y][z] = null; + } + } + } + } + @Override protected boolean partOfMask(int x, int y, int z, BlockState currentState) { if (cache[x][y][z] == null) { diff --git a/src/api/java/baritone/api/schematic/SubstituteSchematic.java b/src/api/java/baritone/api/schematic/SubstituteSchematic.java new file mode 100644 index 000000000..57679a61b --- /dev/null +++ b/src/api/java/baritone/api/schematic/SubstituteSchematic.java @@ -0,0 +1,89 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.schematic; + +import net.minecraft.block.AirBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; +import net.minecraft.state.IProperty; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SubstituteSchematic extends AbstractSchematic { + + private final ISchematic schematic; + private final Map> substitutions; + private final Map> blockStateCache = new HashMap<>(); + + public SubstituteSchematic(ISchematic schematic, Map> substitutions) { + super(schematic.widthX(), schematic.heightY(), schematic.lengthZ()); + this.schematic = schematic; + this.substitutions = substitutions; + } + + @Override + public boolean inSchematic(int x, int y, int z, BlockState currentState) { + return schematic.inSchematic(x, y, z, currentState); + } + + @Override + public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { + BlockState desired = schematic.desiredState(x, y, z, current, approxPlaceable); + Block desiredBlock = desired.getBlock(); + if (!substitutions.containsKey(desiredBlock)) { + return desired; + } + List substitutes = substitutions.get(desiredBlock); + if (substitutes.contains(current.getBlock()) && !(current.getBlock() instanceof AirBlock)) {// don't preserve air, it's almost always there and almost never wanted + return withBlock(desired, current.getBlock()); + } + for (Block substitute : substitutes) { + if (substitute instanceof AirBlock) { + return current.getBlock() instanceof AirBlock ? current : Blocks.AIR.getDefaultState(); // can always "place" air + } + for (BlockState placeable : approxPlaceable) { + if (substitute.equals(placeable.getBlock())) { + return withBlock(desired, placeable.getBlock()); + } + } + } + return substitutes.get(0).getDefaultState(); + } + + private BlockState withBlock(BlockState state, Block block) { + if (blockStateCache.containsKey(state) && blockStateCache.get(state).containsKey(block)) { + return blockStateCache.get(state).get(block); + } + Collection> properties = state.getBlock().getStateContainer().getProperties(); + BlockState newState = block.getDefaultState(); + for (IProperty property : properties) { + try { + newState = copySingleProp(state, newState, property); + } catch (IllegalArgumentException e) { //property does not exist for target block + } + } + blockStateCache.computeIfAbsent(state, s -> new HashMap()).put(block, newState); + return newState; + } + private > BlockState copySingleProp(BlockState fromState, BlockState toState, IProperty prop) { + return toState.with(prop, fromState.get(prop)); + } +} diff --git a/src/api/java/baritone/api/utils/Helper.java b/src/api/java/baritone/api/utils/Helper.java index 2090c3f31..b10032df9 100755 --- a/src/api/java/baritone/api/utils/Helper.java +++ b/src/api/java/baritone/api/utils/Helper.java @@ -18,7 +18,6 @@ package baritone.api.utils; import baritone.api.BaritoneAPI; -import baritone.api.utils.gui.BaritoneToast; import net.minecraft.client.Minecraft; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; @@ -71,7 +70,7 @@ public interface Helper { * @param message The message to display in the popup */ default void logToast(ITextComponent title, ITextComponent message) { - mc.execute(() -> BaritoneToast.addOrUpdate(mc.getToastGui(), title, message, BaritoneAPI.getSettings().toastTimer.value)); + mc.execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message)); } /** @@ -93,6 +92,48 @@ public interface Helper { logToast(Helper.getPrefix(), new StringTextComponent(message)); } + /** + * Send a message as a desktop notification + * + * @param message The message to display in the notification + */ + default void logNotification(String message) { + logNotification(message, false); + } + + /** + * Send a message as a desktop notification + * + * @param message The message to display in the notification + * @param error Whether to log as an error + */ + default void logNotification(String message, boolean error) { + if (BaritoneAPI.getSettings().desktopNotifications.value) { + logNotificationDirect(message, error); + } + } + + /** + * Send a message as a desktop notification regardless of desktopNotifications + * (should only be used for critically important messages) + * + * @param message The message to display in the notification + */ + default void logNotificationDirect(String message) { + logNotificationDirect(message, false); + } + + /** + * Send a message as a desktop notification regardless of desktopNotifications + * (should only be used for critically important messages) + * + * @param message The message to display in the notification + * @param error Whether to log as an error + */ + default void logNotificationDirect(String message, boolean error) { + mc.execute(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error)); + } + /** * Send a message to chat only if chatDebug is on * diff --git a/src/main/java/baritone/utils/NotificationHelper.java b/src/api/java/baritone/api/utils/NotificationHelper.java similarity index 99% rename from src/main/java/baritone/utils/NotificationHelper.java rename to src/api/java/baritone/api/utils/NotificationHelper.java index 54abbf87f..f0ec336dd 100644 --- a/src/main/java/baritone/utils/NotificationHelper.java +++ b/src/api/java/baritone/api/utils/NotificationHelper.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.utils; +package baritone.api.utils; import org.apache.commons.lang3.SystemUtils; diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 4d5de3c0e..9b535d2df 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -38,6 +38,7 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; @@ -51,6 +52,7 @@ public class SettingsUtil { private static final Path SETTINGS_PATH = Minecraft.getInstance().gameDir.toPath().resolve("baritone").resolve("settings.txt"); private static final Pattern SETTING_PATTERN = Pattern.compile("^(?[^ ]+) +(?.+)"); // key and value split by the first space + private static final String[] JAVA_ONLY_SETTINGS = {"logger", "notifier", "toaster"}; private static boolean isComment(String line) { @@ -113,7 +115,7 @@ public class SettingsUtil { System.out.println("NULL SETTING?" + setting.getName()); continue; } - if (setting.getName().equals("logger")) { + if (javaOnlySetting(setting)) { continue; // NO } if (setting.value == setting.defaultValue) { @@ -167,13 +169,28 @@ public class SettingsUtil { } public static String settingToString(Settings.Setting setting) throws IllegalStateException { - if (setting.getName().equals("logger")) { - return "logger"; + if (javaOnlySetting(setting)) { + return setting.getName(); } return setting.getName() + " " + settingValueToString(setting); } + /** + * This should always be the same as whether the setting can be parsed from or serialized to a string + * + * @param the setting + * @return true if the setting can not be set or read by the user + */ + public static boolean javaOnlySetting(Settings.Setting setting) { + for (String name : JAVA_ONLY_SETTINGS) { // no JAVA_ONLY_SETTINGS.contains(...) because that would be case sensitive + if (setting.getName().equalsIgnoreCase(name)) { + return true; + } + } + return false; + } + public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException { Settings.Setting setting = settings.byLowerName.get(settingName); if (setting == null) { @@ -263,6 +280,36 @@ public class SettingsUtil { public boolean accepts(Type type) { return List.class.isAssignableFrom(TypeUtils.resolveBaseClass(type)); } + }, + MAPPING() { + @Override + public Object parse(ParserContext context, String raw) { + Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1]; + Parser keyParser = Parser.getParser(keyType); + Parser valueParser = Parser.getParser(valueType); + + return Stream.of(raw.split(",(?=[^,]*->)")) + .map(s -> s.split("->")) + .collect(Collectors.toMap(s -> keyParser.parse(context, s[0]), s -> valueParser.parse(context, s[1]))); + } + + @Override + public String toString(ParserContext context, Object value) { + Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1]; + Parser keyParser = Parser.getParser(keyType); + Parser valueParser = Parser.getParser(valueType); + + return ((Map) value).entrySet().stream() + .map(o -> keyParser.toString(context, o.getKey()) + "->" + valueParser.toString(context, o.getValue())) + .collect(Collectors.joining(",")); + } + + @Override + public boolean accepts(Type type) { + return Map.class.isAssignableFrom(TypeUtils.resolveBaseClass(type)); + } }; private final Class cla$$; diff --git a/src/api/java/baritone/api/utils/gui/BaritoneToast.java b/src/api/java/baritone/api/utils/gui/BaritoneToast.java index 04aa780ba..3b300444c 100644 --- a/src/api/java/baritone/api/utils/gui/BaritoneToast.java +++ b/src/api/java/baritone/api/utils/gui/BaritoneToast.java @@ -71,4 +71,8 @@ public class BaritoneToast implements IToast { baritonetoast.setDisplayedText(title, subtitle); } } + + public static void addOrUpdate(ITextComponent title, ITextComponent subtitle) { + addOrUpdate(net.minecraft.client.Minecraft.getInstance().getToastGui(), title, subtitle, baritone.api.BaritoneAPI.getSettings().toastTimer.value); + } } diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index f7b44556c..378de0e08 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -68,7 +68,6 @@ public class Baritone implements IBaritone { private PathingBehavior pathingBehavior; private LookBehavior lookBehavior; - private MemoryBehavior memoryBehavior; private InventoryBehavior inventoryBehavior; private InputOverrideHandler inputOverrideHandler; @@ -100,7 +99,6 @@ public class Baritone implements IBaritone { // the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist pathingBehavior = new PathingBehavior(this); lookBehavior = new LookBehavior(this); - memoryBehavior = new MemoryBehavior(this); inventoryBehavior = new InventoryBehavior(this); inputOverrideHandler = new InputOverrideHandler(this); } @@ -151,10 +149,6 @@ public class Baritone implements IBaritone { return this.playerContext; } - public MemoryBehavior getMemoryBehavior() { - return this.memoryBehavior; - } - @Override public FollowProcess getFollowProcess() { return this.followProcess; diff --git a/src/main/java/baritone/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index 97172d309..614ba0d7a 100644 --- a/src/main/java/baritone/behavior/InventoryBehavior.java +++ b/src/main/java/baritone/behavior/InventoryBehavior.java @@ -18,6 +18,7 @@ package baritone.behavior; import baritone.Baritone; +import baritone.api.BaritoneAPI; import baritone.api.event.events.TickEvent; import baritone.utils.ToolSet; import net.minecraft.block.Block; @@ -115,6 +116,9 @@ public final class InventoryBehavior extends Behavior { if (stack.isEmpty()) { continue; } + if (Baritone.settings().itemSaver.value && (stack.getDamage() + Baritone.settings().itemSaverThreshold.value) >= stack.getMaxDamage() && stack.getMaxDamage() > 1) { + continue; + } if (cla$$.isInstance(stack.getItem())) { double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants if (speed > bestSpeed) { @@ -152,6 +156,10 @@ public final class InventoryBehavior extends Behavior { } public boolean throwaway(boolean select, Predicate desired) { + return throwaway(select, desired, Baritone.settings().allowInventory.value); + } + + public boolean throwaway(boolean select, Predicate desired, boolean allowInventory) { ClientPlayerEntity p = ctx.player(); NonNullList inv = p.inventory.mainInventory; for (int i = 0; i < 9; i++) { @@ -184,6 +192,19 @@ public final class InventoryBehavior extends Behavior { } } } + + if (allowInventory) { + for (int i = 9; i < 36; i++) { + if (desired.test(inv.get(i))) { + swapWithHotBar(i, 7); + if (select) { + p.inventory.currentItem = 7; + } + return true; + } + } + } + return false; } } diff --git a/src/main/java/baritone/behavior/MemoryBehavior.java b/src/main/java/baritone/behavior/MemoryBehavior.java deleted file mode 100644 index de1dace42..000000000 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.behavior; - -import baritone.Baritone; -import baritone.api.cache.Waypoint; -import baritone.api.event.events.BlockInteractEvent; -import baritone.api.utils.BetterBlockPos; -import baritone.cache.ContainerMemory; -import baritone.utils.BlockStateInterface; -import net.minecraft.block.BedBlock; -import net.minecraft.item.ItemStack; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - - -/** - * doesn't work for horse inventories :^) - * - * @author Brady - * @since 8/6/2018 - */ -public final class MemoryBehavior extends Behavior { - - public MemoryBehavior(Baritone baritone) { - super(baritone); - } - - @Override - public void onBlockInteract(BlockInteractEvent event) { - if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(ctx, event.getPos()) instanceof BedBlock) { - baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, BetterBlockPos.from(event.getPos()))); - } - } - - @Override - public void onPlayerDeath() { - baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet())); - } - - public EnderChestMemory getCurrent() { - Path path = baritone.getWorldProvider().getCurrentWorld().directory; - return EnderChestMemory.getByServerAndPlayer(path.getParent(), ctx.player().getUniqueID()); - } - - public static class EnderChestMemory { - - private static final Map memory = new HashMap<>(); - private final Path enderChest; - private List contents; - - private EnderChestMemory(Path enderChest) { - this.enderChest = enderChest; - System.out.println("Echest storing in " + enderChest); - try { - this.contents = ContainerMemory.readItemStacks(Files.readAllBytes(enderChest)); - } catch (IOException e) { - e.printStackTrace(); - System.out.println("CANNOT read echest =( =("); - this.contents = null; - } - } - - public synchronized void save() { - System.out.println("Saving"); - if (contents != null) { - 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) { - return memory.computeIfAbsent(serverStorage.resolve("echests").resolve(player.toString()), EnderChestMemory::new); - } - } -} diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 50ca7425f..f9c56c5a4 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -52,6 +52,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, private Goal goal; private CalculationContext context; + /*eta*/ + private int ticksElapsedSoFar; + private BetterBlockPos startPosition; + private boolean safeToCancel; private boolean pauseRequestedLastTick; private boolean unpausedLastTick; @@ -98,6 +102,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, expectedSegmentStart = pathStart(); baritone.getPathingControlManager().preTick(); tickPath(); + ticksElapsedSoFar++; dispatchEvents(); } @@ -372,6 +377,40 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, return context; } + public Optional estimatedTicksToGoal() { + BetterBlockPos currentPos = ctx.playerFeet(); + if (goal == null || currentPos == null || startPosition == null) { + return Optional.empty(); + } + if (goal.isInGoal(ctx.playerFeet())) { + resetEstimatedTicksToGoal(); + return Optional.of(0.0); + } + if (ticksElapsedSoFar == 0) { + return Optional.empty(); + } + double current = goal.heuristic(currentPos.x, currentPos.y, currentPos.z); + double start = goal.heuristic(startPosition.x, startPosition.y, startPosition.z); + if (current == start) {// can't check above because current and start can be equal even if currentPos and startPosition are not + return Optional.empty(); + } + double eta = Math.abs(current - goal.heuristic()) * ticksElapsedSoFar / Math.abs(start - current); + return Optional.of(eta); + } + + private void resetEstimatedTicksToGoal() { + resetEstimatedTicksToGoal(expectedSegmentStart); + } + + private void resetEstimatedTicksToGoal(BlockPos start) { + resetEstimatedTicksToGoal(new BetterBlockPos(start)); + } + + private void resetEstimatedTicksToGoal(BetterBlockPos start) { + ticksElapsedSoFar = 0; + startPosition = start; + } + /** * See issue #209 * @@ -468,6 +507,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, if (executor.get().getPath().positions().contains(expectedSegmentStart)) { queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING); current = executor.get(); + resetEstimatedTicksToGoal(start); } else { logDebug("Warning: discarding orphan path segment with incorrect start"); } diff --git a/src/main/java/baritone/cache/ChunkPacker.java b/src/main/java/baritone/cache/ChunkPacker.java index 7387dc1d2..33eafc291 100644 --- a/src/main/java/baritone/cache/ChunkPacker.java +++ b/src/main/java/baritone/cache/ChunkPacker.java @@ -123,7 +123,7 @@ public final class ChunkPacker { return PathingBlockType.AVOID; } if (x == 0 || x == 15 || z == 0 || z == 15) { - Vec3d flow = state.getFluidState().getFlow(chunk.getWorld(), new BlockPos(x + chunk.getPos().x << 4, y, z + chunk.getPos().z << 4)); + Vec3d flow = state.getFluidState().getFlow(chunk.getWorld(), new BlockPos(x + (chunk.getPos().x << 4), y, z + (chunk.getPos().z << 4))); if (flow.x != 0.0 || flow.z != 0.0) { return PathingBlockType.WATER; } diff --git a/src/main/java/baritone/cache/ContainerMemory.java b/src/main/java/baritone/cache/ContainerMemory.java deleted file mode 100644 index e79435e3a..000000000 --- a/src/main/java/baritone/cache/ContainerMemory.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * This file is part of Baritone. - * - * Baritone is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Baritone is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Baritone. If not, see . - */ - -package baritone.cache; - -import baritone.Baritone; -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.NoSuchFileException; -import java.nio.file.Path; -import java.util.*; - -public class ContainerMemory implements IContainerMemory { - - private final Path saveTo; - /** - * The current remembered inventories - */ - private final Map inventories = new HashMap<>(); - - - public ContainerMemory(Path saveTo) { - this.saveTo = saveTo; - try { - read(Files.readAllBytes(saveTo)); - } catch (NoSuchFileException ignored) { - inventories.clear(); - } 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 { - if (!Baritone.settings().containerMemory.value) { - return; - } - ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE); - PacketBuffer out = new PacketBuffer(buf); - out.writeInt(inventories.size()); - for (Map.Entry 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 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 getRememberedInventories() { - // make a copy since this map is modified from the packet thread - return new HashMap<>(inventories); - } - - public static List readItemStacks(byte[] bytes) throws IOException { - PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes)); - return readItemStacks(in); - } - - public static List readItemStacks(PacketBuffer in) throws IOException { - int count = in.readInt(); - List result = new ArrayList<>(); - for (int i = 0; i < count; i++) { - result.add(in.readItemStack()); - } - return result; - } - - public static byte[] writeItemStacks(List 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 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. - *

- * 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 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 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)); - } - } -} diff --git a/src/main/java/baritone/cache/WorldData.java b/src/main/java/baritone/cache/WorldData.java index 30fe8bd0d..cbdda3687 100644 --- a/src/main/java/baritone/cache/WorldData.java +++ b/src/main/java/baritone/cache/WorldData.java @@ -19,7 +19,6 @@ package baritone.cache; import baritone.Baritone; import baritone.api.cache.ICachedWorld; -import baritone.api.cache.IContainerMemory; import baritone.api.cache.IWaypointCollection; import baritone.api.cache.IWorldData; @@ -35,7 +34,6 @@ public class WorldData implements IWorldData { public final CachedWorld cache; private final WaypointCollection waypoints; - private final ContainerMemory containerMemory; //public final MapData map; public final Path directory; public final int dimension; @@ -44,7 +42,6 @@ public class WorldData implements IWorldData { this.directory = directory; this.cache = new CachedWorld(directory.resolve("cache"), dimension); this.waypoints = new WaypointCollection(directory.resolve("waypoints")); - this.containerMemory = new ContainerMemory(directory.resolve("containers")); this.dimension = dimension; } @@ -53,15 +50,6 @@ public class WorldData implements IWorldData { System.out.println("Started saving the world in a new thread"); 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 @@ -73,9 +61,4 @@ public class WorldData implements IWorldData { public IWaypointCollection getWaypoints() { return this.waypoints; } - - @Override - public IContainerMemory getContainerMemory() { - return this.containerMemory; - } } diff --git a/src/main/java/baritone/cache/WorldProvider.java b/src/main/java/baritone/cache/WorldProvider.java index dfc671532..bcf399673 100644 --- a/src/main/java/baritone/cache/WorldProvider.java +++ b/src/main/java/baritone/cache/WorldProvider.java @@ -74,7 +74,14 @@ public class WorldProvider implements IWorldProvider, Helper { directory = new File(directory, "baritone"); readme = directory; } else { // Otherwise, the server must be remote... - String folderName = mc.isConnectedToRealms() ? "realms" : mc.getCurrentServerData().serverIP; + String folderName; + if (mc.getCurrentServerData() != null) { + folderName = mc.isConnectedToRealms() ? "realms" : mc.getCurrentServerData().serverIP; + } else { + //replaymod causes null currentServerData and false singleplayer. + currentWorld = null; + return; + } if (SystemUtils.IS_OS_WINDOWS) { folderName = folderName.replace(":", "_"); } diff --git a/src/main/java/baritone/command/ExampleBaritoneControl.java b/src/main/java/baritone/command/ExampleBaritoneControl.java index b132d3e7a..43982bfc2 100644 --- a/src/main/java/baritone/command/ExampleBaritoneControl.java +++ b/src/main/java/baritone/command/ExampleBaritoneControl.java @@ -124,7 +124,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener } } else if (argc.hasExactlyOne()) { for (Settings.Setting setting : settings.allSettings) { - if (setting.getName().equals("logger")) { + if (SettingsUtil.javaOnlySetting(setting)) { continue; } if (setting.getName().equalsIgnoreCase(pair.getA())) { @@ -177,7 +177,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener .stream(); } Settings.Setting setting = settings.byLowerName.get(argc.getString().toLowerCase(Locale.US)); - if (setting != null) { + if (setting != null && !SettingsUtil.javaOnlySetting(setting)) { if (setting.getValueClass() == Boolean.class) { TabCompleteHelper helper = new TabCompleteHelper(); if ((Boolean) setting.value) { diff --git a/src/main/java/baritone/command/defaults/DefaultCommands.java b/src/main/java/baritone/command/defaults/DefaultCommands.java index 41c58b003..e998dcc97 100644 --- a/src/main/java/baritone/command/defaults/DefaultCommands.java +++ b/src/main/java/baritone/command/defaults/DefaultCommands.java @@ -38,6 +38,7 @@ public final class DefaultCommands { new GotoCommand(baritone), new PathCommand(baritone), new ProcCommand(baritone), + new ETACommand(baritone), new VersionCommand(baritone), new RepackCommand(baritone), new BuildCommand(baritone), @@ -50,7 +51,6 @@ public final class DefaultCommands { new TunnelCommand(baritone), new RenderCommand(baritone), new FarmCommand(baritone), - new ChestsCommand(baritone), new FollowCommand(baritone), new ExploreFilterCommand(baritone), new ReloadAllCommand(baritone), diff --git a/src/main/java/baritone/command/defaults/ChestsCommand.java b/src/main/java/baritone/command/defaults/ETACommand.java similarity index 53% rename from src/main/java/baritone/command/defaults/ChestsCommand.java rename to src/main/java/baritone/command/defaults/ETACommand.java index b4dcda749..3c16bd113 100644 --- a/src/main/java/baritone/command/defaults/ChestsCommand.java +++ b/src/main/java/baritone/command/defaults/ETACommand.java @@ -18,47 +18,39 @@ package baritone.command.defaults; import baritone.api.IBaritone; -import baritone.api.cache.IRememberedInventory; +import baritone.api.pathing.calc.IPathingControlManager; +import baritone.api.process.IBaritoneProcess; +import baritone.api.behavior.IPathingBehavior; import baritone.api.command.Command; -import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; -import baritone.api.utils.BetterBlockPos; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.ITextComponent; +import baritone.api.command.argument.IArgConsumer; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.stream.Stream; -public class ChestsCommand extends Command { +public class ETACommand extends Command { - public ChestsCommand(IBaritone baritone) { - super(baritone, "chests"); + public ETACommand(IBaritone baritone) { + super(baritone, "eta"); } @Override public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(0); - Set> entries = - ctx.worldData().getContainerMemory().getRememberedInventories().entrySet(); - if (entries.isEmpty()) { - throw new CommandInvalidStateException("No remembered inventories"); - } - for (Map.Entry entry : entries) { - // betterblockpos has censoring - BetterBlockPos pos = new BetterBlockPos(entry.getKey()); - IRememberedInventory inv = entry.getValue(); - logDirect(pos.toString()); - for (ItemStack item : inv.getContents()) { - ITextComponent component = item.getTextComponent(); - component.appendText(String.format(" x %d", item.getCount())); - logDirect(component); - } + IPathingControlManager pathingControlManager = baritone.getPathingControlManager(); + IBaritoneProcess process = pathingControlManager.mostRecentInControl().orElse(null); + if (process == null) { + throw new CommandInvalidStateException("No process in control"); } + IPathingBehavior pathingBehavior = baritone.getPathingBehavior(); + logDirect(String.format( + "Next segment: %.2f\n" + + "Goal: %.2f", + pathingBehavior.ticksRemainingInSegment().orElse(-1.0), + pathingBehavior.estimatedTicksToGoal().orElse(-1.0) + )); } @Override @@ -68,16 +60,19 @@ public class ChestsCommand extends Command { @Override public String getShortDesc() { - return "Display remembered inventories"; + return "View the current ETA"; } @Override public List getLongDesc() { return Arrays.asList( - "The chests command lists remembered inventories, I guess?", + "The ETA command provides information about the estimated time until the next segment.", + "and the goal", + "", + "Be aware that the ETA to your goal is really unprecise", "", "Usage:", - "> chests" + "> eta - View ETA, if present" ); } } diff --git a/src/main/java/baritone/command/defaults/ExecutionControlCommands.java b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java index 1b024c3b8..8a53e7d41 100644 --- a/src/main/java/baritone/command/defaults/ExecutionControlCommands.java +++ b/src/main/java/baritone/command/defaults/ExecutionControlCommands.java @@ -112,7 +112,7 @@ public class ExecutionControlCommands { ); } }; - resumeCommand = new Command(baritone, "resume", "r") { + resumeCommand = new Command(baritone, "resume", "r", "unpause") { @Override public void execute(String label, IArgConsumer args) throws CommandException { args.requireMax(0); diff --git a/src/main/java/baritone/command/defaults/FindCommand.java b/src/main/java/baritone/command/defaults/FindCommand.java index a415b9b15..a6b6a7b7a 100644 --- a/src/main/java/baritone/command/defaults/FindCommand.java +++ b/src/main/java/baritone/command/defaults/FindCommand.java @@ -72,10 +72,10 @@ public class FindCommand extends Command { @Override public List getLongDesc() { return Arrays.asList( - "", + "The find command searches through Baritone's cache and attempts to find the location of the block.", "", "Usage:", - "> " + "> find - Find positions of a certain block" ); } } diff --git a/src/main/java/baritone/command/defaults/FollowCommand.java b/src/main/java/baritone/command/defaults/FollowCommand.java index 50844165e..8ea599f7a 100644 --- a/src/main/java/baritone/command/defaults/FollowCommand.java +++ b/src/main/java/baritone/command/defaults/FollowCommand.java @@ -24,6 +24,7 @@ import baritone.api.command.argument.IArgConsumer; import baritone.api.command.datatypes.EntityClassById; import baritone.api.command.datatypes.IDatatypeFor; import baritone.api.command.datatypes.NearbyPlayer; +import baritone.api.command.exception.CommandErrorMessageException; import baritone.api.command.exception.CommandException; import baritone.api.command.helpers.TabCompleteHelper; import net.minecraft.entity.Entity; @@ -61,7 +62,7 @@ public class FollowCommand extends Command { if (gotten instanceof EntityType) { //noinspection unchecked classes.add((EntityType) gotten); - } else { + } else if (gotten != null) { entities.add((Entity) gotten); } } @@ -75,12 +76,14 @@ public class FollowCommand extends Command { if (group != null) { logDirect(String.format("Following all %s", group.name().toLowerCase(Locale.US))); } else { - logDirect("Following these types of entities:"); if (classes.isEmpty()) { + if (entities.isEmpty()) throw new NoEntitiesException(); + logDirect("Following these entities:"); entities.stream() .map(Entity::toString) .forEach(this::logDirect); } else { + logDirect("Following these types of entities:"); classes.stream() .map(Registry.ENTITY_TYPE::getKey) .map(Objects::requireNonNull) @@ -157,4 +160,12 @@ public class FollowCommand extends Command { this.datatype = datatype; } } + + public static class NoEntitiesException extends CommandErrorMessageException { + + protected NoEntitiesException() { + super("No valid entities in range!"); + } + + } } diff --git a/src/main/java/baritone/command/defaults/SchematicaCommand.java b/src/main/java/baritone/command/defaults/SchematicaCommand.java index ae5cac47f..842a30131 100644 --- a/src/main/java/baritone/command/defaults/SchematicaCommand.java +++ b/src/main/java/baritone/command/defaults/SchematicaCommand.java @@ -51,7 +51,7 @@ public class SchematicaCommand extends Command { @Override public List getLongDesc() { return Arrays.asList( - "Builds the schematica currently open in Schematica.", + "Builds the schematic currently open in Schematica.", "", "Usage:", "> schematica" diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java index 4a8e7bb71..24fdb01a4 100644 --- a/src/main/java/baritone/command/defaults/SelCommand.java +++ b/src/main/java/baritone/command/defaults/SelCommand.java @@ -37,7 +37,10 @@ import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BlockOptionalMeta; import baritone.api.utils.BlockOptionalMetaLookup; import baritone.utils.IRenderer; +import baritone.utils.BlockStateInterface; +import baritone.utils.schematic.StaticSchematic; import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -53,6 +56,8 @@ public class SelCommand extends Command { private ISelectionManager manager = baritone.getSelectionManager(); private BetterBlockPos pos1 = null; + private ISchematic clipboard = null; + private Vec3i clipboardOffset = null; public SelCommand(IBaritone baritone) { super(baritone, "sel", "selection", "s"); @@ -158,6 +163,56 @@ public class SelCommand extends Command { } baritone.getBuilderProcess().build("Fill", composite, origin); logDirect("Filling now"); + } else if (action == Action.COPY) { + BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet(); + BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos; + args.requireMax(0); + ISelection[] selections = manager.getSelections(); + if (selections.length < 1) { + throw new CommandInvalidStateException("No selections"); + } + BlockStateInterface bsi = new BlockStateInterface(ctx); + BetterBlockPos origin = selections[0].min(); + CompositeSchematic composite = new CompositeSchematic(0, 0, 0); + for (ISelection selection : selections) { + BetterBlockPos min = selection.min(); + origin = new BetterBlockPos( + Math.min(origin.x, min.x), + Math.min(origin.y, min.y), + Math.min(origin.z, min.z) + ); + } + for (ISelection selection : selections) { + Vec3i size = selection.size(); + BetterBlockPos min = selection.min(); + BlockState[][][] blockstates = new BlockState[size.getX()][size.getZ()][size.getY()]; + for (int x = 0; x < size.getX(); x++) { + for (int y = 0; y < size.getY(); y++) { + for (int z = 0; z < size.getZ(); z++) { + blockstates[x][z][y] = bsi.get0(min.x + x, min.y + y, min.z + z); + } + } + } + ISchematic schematic = new StaticSchematic(){{ + states = blockstates; + x = size.getX(); + y = size.getY(); + z = size.getZ(); + }}; + composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z); + } + clipboard = composite; + clipboardOffset = origin.subtract(pos); + logDirect("Selection copied"); + } else if (action == Action.PASTE) { + BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet(); + BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos; + args.requireMax(0); + if (clipboard == null) { + throw new CommandInvalidStateException("You need to copy a selection first"); + } + baritone.getBuilderProcess().build("Fill", clipboard, pos.add(clipboardOffset)); + logDirect("Building now"); } else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) { args.requireExactly(3); TransformTarget transformTarget = TransformTarget.getByName(args.getString()); @@ -252,6 +307,8 @@ public class SelCommand extends Command { "> sel shell/shl [block] - The same as walls, but fills in a ceiling and floor too.", "> sel cleararea/ca - Basically 'set air'.", "> sel replace/r - Replaces blocks with another block.", + "> sel copy/cp - Copy the selected area relative to the specified or your position.", + "> sel paste/p - Build the copied area relative to the specified or your position.", "", "> sel expand - Expand the targets.", "> sel contract - Contract the targets.", @@ -270,6 +327,8 @@ public class SelCommand extends Command { CLEARAREA("cleararea", "ca"), REPLACE("replace", "r"), EXPAND("expand", "ex"), + COPY("copy", "cp"), + PASTE("paste", "p"), CONTRACT("contract", "ct"), SHIFT("shift", "sh"); private final String[] names; diff --git a/src/main/java/baritone/command/defaults/SetCommand.java b/src/main/java/baritone/command/defaults/SetCommand.java index 9319dc9df..dad7a326b 100644 --- a/src/main/java/baritone/command/defaults/SetCommand.java +++ b/src/main/java/baritone/command/defaults/SetCommand.java @@ -23,6 +23,7 @@ import baritone.api.Settings; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.exception.CommandException; +import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.command.exception.CommandInvalidTypeException; import baritone.api.command.helpers.Paginator; import baritone.api.command.helpers.TabCompleteHelper; @@ -40,8 +41,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; -import static baritone.api.utils.SettingsUtil.settingTypeToString; -import static baritone.api.utils.SettingsUtil.settingValueToString; +import static baritone.api.utils.SettingsUtil.*; public class SetCommand extends Command { @@ -65,7 +65,7 @@ public class SetCommand extends Command { args.requireMax(1); List toPaginate = (viewModified ? SettingsUtil.modifiedSettings(Baritone.settings()) : Baritone.settings().allSettings).stream() - .filter(s -> !s.getName().equals("logger")) + .filter(s -> !javaOnlySetting(s)) .filter(s -> s.getName().toLowerCase(Locale.US).contains(search.toLowerCase(Locale.US))) .sorted((s1, s2) -> String.CASE_INSENSITIVE_ORDER.compare(s1.getName(), s2.getName())) .collect(Collectors.toList()); @@ -88,6 +88,7 @@ public class SetCommand extends Command { hoverComponent.appendText(setting.getName()); hoverComponent.appendText(String.format("\nType: %s", settingTypeToString(setting))); hoverComponent.appendText(String.format("\n\nValue:\n%s", settingValueToString(setting))); + hoverComponent.appendText(String.format("\n\nDefault Value:\n%s", settingDefaultToString(setting))); String commandSuggestion = Baritone.settings().prefix.value + String.format("set %s ", setting.getName()); ITextComponent component = new StringTextComponent(setting.getName()); component.getStyle().setColor(TextFormatting.GRAY); @@ -128,6 +129,12 @@ public class SetCommand extends Command { if (setting == null) { throw new CommandInvalidTypeException(args.consumed(), "a valid setting"); } + if (javaOnlySetting(setting)) { + // ideally it would act as if the setting didn't exist + // but users will see it in Settings.java or its javadoc + // so at some point we have to tell them or they will see it as a bug + throw new CommandInvalidStateException(String.format("Setting %s can only be used via the api.", setting.getName())); + } if (!doingSomething && !args.hasAny()) { logDirect(String.format("Value of setting %s:", setting.getName())); logDirect(settingValueToString(setting)); diff --git a/src/main/java/baritone/command/defaults/WaypointsCommand.java b/src/main/java/baritone/command/defaults/WaypointsCommand.java index acb33c9df..23c5523e4 100644 --- a/src/main/java/baritone/command/defaults/WaypointsCommand.java +++ b/src/main/java/baritone/command/defaults/WaypointsCommand.java @@ -17,9 +17,11 @@ package baritone.command.defaults; +import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.cache.IWaypoint; import baritone.api.cache.Waypoint; +import baritone.api.cache.IWorldData; import baritone.api.command.Command; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.datatypes.ForWaypoints; @@ -41,12 +43,15 @@ import net.minecraft.util.text.event.HoverEvent; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; public class WaypointsCommand extends Command { + private Map> deletedWaypoints = new HashMap<>(); + public WaypointsCommand(IBaritone baritone) { super(baritone, "waypoints", "waypoint", "wp"); } @@ -125,11 +130,13 @@ public class WaypointsCommand extends Command { ); } } else if (action == Action.SAVE) { - IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString()); + IWaypoint.Tag tag = args.hasAny() ? IWaypoint.Tag.getByName(args.peekString()) : null; if (tag == null) { - throw new CommandInvalidStateException(String.format("'%s' is not a tag ", args.consumedString())); + tag = IWaypoint.Tag.USER; + } else { + args.get(); } - String name = args.hasAny() ? args.getString() : ""; + String name = (args.hasExactlyOne() || args.hasExactly(4)) ? args.getString() : ""; BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, ctx.playerFeet()) : ctx.playerFeet(); @@ -147,7 +154,42 @@ public class WaypointsCommand extends Command { for (IWaypoint waypoint : waypoints) { ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint); } - logDirect(String.format("Cleared %d waypoints", waypoints.length)); + deletedWaypoints.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), k -> new ArrayList<>()).addAll(Arrays.asList(waypoints)); + ITextComponent textComponent = new StringTextComponent(String.format("Cleared %d waypoints, click to restore them", waypoints.length)); + textComponent.getStyle().setClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + String.format( + "%s%s restore @ %s", + FORCE_COMMAND_PREFIX, + label, + Stream.of(waypoints).map(wp -> Long.toString(wp.getCreationTimestamp())).collect(Collectors.joining(" ")) + ) + )); + logDirect(textComponent); + } else if (action == Action.RESTORE) { + List waypoints = new ArrayList<>(); + List deletedWaypoints = this.deletedWaypoints.getOrDefault(baritone.getWorldProvider().getCurrentWorld(), Collections.emptyList()); + if (args.peekString().equals("@")) { + args.get(); + // no args.requireMin(1) because if the user clears an empty tag there is nothing to restore + while (args.hasAny()) { + long timestamp = args.getAs(Long.class); + for (IWaypoint waypoint : deletedWaypoints) { + if (waypoint.getCreationTimestamp() == timestamp) { + waypoints.add(waypoint); + break; + } + } + } + } else { + args.requireExactly(1); + int size = deletedWaypoints.size(); + int amount = Math.min(size, args.getAs(Integer.class)); + waypoints = new ArrayList<>(deletedWaypoints.subList(size - amount, size)); + } + waypoints.forEach(ForWaypoints.waypoints(this.baritone)::addWaypoint); + deletedWaypoints.removeIf(waypoints::contains); + logDirect(String.format("Restored %d waypoints", waypoints.size())); } else { IWaypoint[] waypoints = args.getDatatypeFor(ForWaypoints.INSTANCE); IWaypoint waypoint = null; @@ -216,6 +258,20 @@ public class WaypointsCommand extends Command { waypoint.getCreationTimestamp() ) )); + ITextComponent recreateComponent = new StringTextComponent("Click to show a command to recreate this waypoint"); + recreateComponent.getStyle().setClickEvent(new ClickEvent( + ClickEvent.Action.SUGGEST_COMMAND, + String.format( + "%s%s save %s %s %s %s %s", + Baritone.settings().prefix.value, // This uses the normal prefix because it is run by the user. + label, + waypoint.getTag().getName(), + waypoint.getName(), + waypoint.getLocation().x, + waypoint.getLocation().y, + waypoint.getLocation().z + ) + )); ITextComponent backComponent = new StringTextComponent("Click to return to the waypoints list"); backComponent.getStyle().setClickEvent(new ClickEvent( ClickEvent.Action.RUN_COMMAND, @@ -227,10 +283,22 @@ public class WaypointsCommand extends Command { )); logDirect(deleteComponent); logDirect(goalComponent); + logDirect(recreateComponent); logDirect(backComponent); } else if (action == Action.DELETE) { ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint); - logDirect("That waypoint has successfully been deleted"); + deletedWaypoints.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), k -> new ArrayList<>()).add(waypoint); + ITextComponent textComponent = new StringTextComponent("That waypoint has successfully been deleted, click to restore it"); + textComponent.getStyle().setClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + String.format( + "%s%s restore @ %s", + FORCE_COMMAND_PREFIX, + label, + waypoint.getCreationTimestamp() + ) + )); + logDirect(textComponent); } else if (action == Action.GOAL) { Goal goal = new GoalBlock(waypoint.getLocation()); baritone.getCustomGoalProcess().setGoal(goal); @@ -262,6 +330,8 @@ public class WaypointsCommand extends Command { .sortAlphabetically() .filterPrefix(args.getString()) .stream(); + } else if (action == Action.RESTORE) { + return Stream.empty(); } else { return args.tabCompleteDatatype(ForWaypoints.INSTANCE); } @@ -289,15 +359,19 @@ public class WaypointsCommand extends Command { "", "Note that the info, delete, and goal commands let you specify a waypoint by tag. If there is more than one waypoint with a certain tag, then they will let you select which waypoint you mean.", "", + "Missing arguments for the save command use the USER tag, creating an unnamed waypoint and your current position as defaults.", + "", "Usage:", "> wp [l/list] - List all waypoints.", - "> wp - Save your current position as an unnamed waypoint with the specified tag.", - "> wp - Save the waypoint with the specified name.", - "> wp - Save the waypoint with the specified name and position.", - "> wp - Show info on a waypoint by tag.", - "> wp - Delete a waypoint by tag.", - "> wp - Set a goal to a waypoint by tag.", - "> wp - Set a goal to a waypoint by tag and start pathing." + "> wp - List all waypoints by tag.", + "> wp - Save an unnamed USER waypoint at your current position", + "> wp [tag] [name] [pos] - Save a waypoint with the specified tag, name and position.", + "> wp - Show info on a waypoint by tag or name.", + "> wp - Delete a waypoint by tag or name.", + "> wp - Restore the last n deleted waypoints.", + "> wp - Delete all waypoints with the specified tag.", + "> wp - Set a goal to a waypoint by tag or name.", + "> wp - Set a goal to a waypoint by tag or name and start pathing." ); } @@ -307,6 +381,7 @@ public class WaypointsCommand extends Command { SAVE("save", "s"), INFO("info", "show", "i"), DELETE("delete", "d"), + RESTORE("restore"), GOAL("goal", "g"), GOTO("goto"); private final String[] names; diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index c54216568..d20b519dc 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -25,7 +25,6 @@ import baritone.api.utils.BetterBlockPos; import baritone.api.utils.Helper; import baritone.api.utils.PathCalculationResult; import baritone.pathing.movement.CalculationContext; -import baritone.utils.NotificationHelper; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Optional; @@ -217,9 +216,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { 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 =("); - if (Baritone.settings().desktopNotifications.value) { - NotificationHelper.notify("No path found =(", true); - } + logNotification("No path found =(", true); } return Optional.empty(); } diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index cd41ed7df..2d84ffad2 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -143,7 +143,6 @@ public class CalculationContext { return COST_INF; } if (!worldBorder.canPlaceAt(x, z)) { - // TODO perhaps MovementHelper.canPlaceAgainst could also use this? return COST_INF; } return placeBlockCost; diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 134b323f1..f41de69c4 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -52,8 +52,12 @@ import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____S public interface MovementHelper extends ActionCosts, Helper { static boolean avoidBreaking(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + if (!bsi.worldBorder.canPlaceAt(x, y)) { + return true; + } Block b = state.getBlock(); - return b == Blocks.ICE // ice becomes water, and water can mess up the path + return Baritone.settings().blocksToDisallowBreaking.value.contains(b) + || b == Blocks.ICE // ice becomes water, and water can mess up the path || b instanceof SilverfishBlock // obvious reasons // call context.get directly with x,y,z. no need to make 5 new BlockPos for no reason || avoidAdjacentBreaking(bsi, x, y + 1, z, true) @@ -137,6 +141,9 @@ public interface MovementHelper extends ActionCosts, Helper { } return true; } + if (block instanceof CauldronBlock) { + return false; + } // every block that overrides isPassable with anything more complicated than a "return true;" or "return false;" // has already been accounted for above // therefore it's safe to not construct a blockpos from our x, y, z ints and instead just pass null @@ -373,6 +380,9 @@ public interface MovementHelper extends ActionCosts, Helper { } static boolean canPlaceAgainst(BlockStateInterface bsi, int x, int y, int z, BlockState state) { + if (!bsi.worldBorder.canPlaceAt(x, z)) { + return false; + } // can we look at the center of a side face of this block and likely be able to place? // (thats how this check is used) // therefore dont include weird things that we technically could place against (like carpet) but practically can't @@ -437,7 +447,7 @@ public interface MovementHelper extends ActionCosts, Helper { * @param ts previously calculated ToolSet */ static void switchToBestToolFor(IPlayerContext ctx, BlockState b, ToolSet ts, boolean preferSilkTouch) { - if (!Baritone.settings().disableAutoTool.value && !Baritone.settings().assumeExternalAutoTool.value) { + if (Baritone.settings().autoTool.value && !Baritone.settings().assumeExternalAutoTool.value) { ctx.player().inventory.currentItem = ts.getBestSlot(b.getBlock(), preferSilkTouch); } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index dae6667f1..0cdb245aa 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -105,15 +105,22 @@ public class MovementParkour extends Movement { maxJump = 3; } } + + // check parkour jumps from smallest to largest for obstacles/walls and landing positions + int verifiedMaxJump = 1; // i - 1 (when i = 2) for (int i = 2; i <= maxJump; i++) { int destX = x + xDiff * i; int destZ = z + zDiff * i; + + // check head/feet if (!MovementHelper.fullyPassable(context, destX, y + 1, destZ)) { - return; + break; } if (!MovementHelper.fullyPassable(context, destX, y + 2, destZ)) { - return; + break; } + + // check for ascend landing position BlockState destInto = context.bsi.get0(destX, y, destZ); if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.setPos(destX, y, destZ), destInto)) { if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) { @@ -121,57 +128,65 @@ public class MovementParkour extends Movement { res.y = y + 1; res.z = destZ; res.cost = i * SPRINT_ONE_BLOCK_COST + context.jumpPenalty; + return; } - return; + break; } + + // check for flat landing position BlockState landingOn = context.bsi.get0(destX, y - 1, destZ); - // farmland needs to be canwalkon otherwise farm can never work at all, but we want to specifically disallow ending a jumy on farmland haha + // farmland needs to be canWalkOn otherwise farm can never work at all, but we want to specifically disallow ending a jump on farmland haha if (landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, landingOn)) { if (checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) { res.x = destX; res.y = y; res.z = destZ; res.cost = costFromJumpDistance(i) + context.jumpPenalty; + return; } - return; + break; } + if (!MovementHelper.fullyPassable(context, destX, y + 3, destZ)) { - return; + break; } + + verifiedMaxJump = i; } - if (maxJump != 4) { - return; - } + + // parkour place starts here if (!context.allowParkourPlace) { return; } - // time 2 pop off with that dank skynet parkour place - int destX = x + 4 * xDiff; - int destZ = z + 4 * zDiff; - BlockState toReplace = context.get(destX, y - 1, destZ); - double placeCost = context.costOfPlacingAt(destX, y - 1, destZ, toReplace); - if (placeCost >= COST_INF) { - return; - } - if (!MovementHelper.isReplaceable(destX, y - 1, destZ, toReplace, context.bsi)) { - return; - } - if (!checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) { - return; - } - for (int i = 0; i < 5; i++) { - 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(); - if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast + // check parkour jumps from largest to smallest for positions to place blocks + for (int i = verifiedMaxJump; i > 1; i--) { + int destX = x + i * xDiff; + int destZ = z + i * zDiff; + BlockState toReplace = context.get(destX, y - 1, destZ); + double placeCost = context.costOfPlacingAt(destX, y - 1, destZ, toReplace); + if (placeCost >= COST_INF) { continue; } - if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { - res.x = destX; - res.y = y; - res.z = destZ; - res.cost = costFromJumpDistance(4) + placeCost + context.jumpPenalty; - return; + if (!MovementHelper.isReplaceable(destX, y - 1, destZ, toReplace, context.bsi)) { + continue; + } + if (!checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) { + continue; + } + for (int j = 0; j < 5; j++) { + int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP[j].getXOffset(); + int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP[j].getYOffset(); + int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP[j].getZOffset(); + if (againstX == destX - xDiff && againstZ == destZ - zDiff) { // we can't turn around that fast + continue; + } + if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { + res.x = destX; + res.y = y; + res.z = destZ; + res.cost = costFromJumpDistance(i) + placeCost + context.jumpPenalty; + return; + } } } } diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index 1ede4d6db..81d889d9d 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -26,6 +26,7 @@ import baritone.api.process.IBuilderProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; import baritone.api.schematic.FillSchematic; +import baritone.api.schematic.SubstituteSchematic; import baritone.api.schematic.ISchematic; import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.format.ISchematicFormat; @@ -39,20 +40,20 @@ import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; -import baritone.utils.NotificationHelper; import baritone.utils.PathingCommandContext; import baritone.utils.schematic.MapArtSchematic; +import baritone.utils.schematic.SelectionSchematic; import baritone.utils.schematic.SchematicSystem; import baritone.utils.schematic.schematica.SchematicaHelper; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import net.minecraft.block.AirBlock; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.FlowingFluidBlock; +import net.minecraft.block.*; import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; +import net.minecraft.state.IProperty; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.Tuple; @@ -89,6 +90,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil this.name = name; this.schematic = schematic; this.realSchematic = null; + if (!Baritone.settings().buildSubstitutes.value.isEmpty()) { + this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value); + } int x = origin.getX(); int y = origin.getY(); int z = origin.getZ(); @@ -140,6 +144,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil parsed = new MapArtSchematic((IStaticSchematic) parsed); } + if (Baritone.settings().buildOnlySelection.value) { + parsed = new SelectionSchematic(parsed, origin, baritone.getSelectionManager().getSelections()); + } + + build(name, parsed, origin); return true; } @@ -150,10 +159,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil Optional> schematic = SchematicaHelper.getOpenSchematic(); if (schematic.isPresent()) { IStaticSchematic s = schematic.get().getA(); + BlockPos origin = schematic.get().getB(); + ISchematic schem = Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s; + if (Baritone.settings().buildOnlySelection.value) { + schem = new SelectionSchematic(schem, origin, baritone.getSelectionManager().getSelections()); + } this.build( schematic.get().getA().toString(), - Baritone.settings().mapArtMode.value ? new MapArtSchematic(s) : s, - schematic.get().getB() + schem, + origin ); } else { logDirect("No schematic currently open"); @@ -359,6 +373,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { + return onTick(calcFailed, isSafeToCancel, 0); + } + + public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) { + if (recursions > 1000) { // onTick calls itself, don't crash + return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH); + } approxPlaceable = approxPlaceable(36); if (baritone.getInputOverrideHandler().isInputForcedDown(Input.CLICK_LEFT)) { ticks = 5; @@ -380,9 +401,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil // layer = realSchematic.heightY() should be everything if (Baritone.settings().layerOrder.value) { // top to bottom maxYInclusive = realSchematic.heightY() - 1; - minYInclusive = realSchematic.heightY() - layer; + minYInclusive = realSchematic.heightY() - layer * Baritone.settings().layerHeight.value; } else { - maxYInclusive = layer - 1; + maxYInclusive = layer * Baritone.settings().layerHeight.value - 1; minYInclusive = 0; } schematic = new ISchematic() { @@ -396,6 +417,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return ISchematic.super.inSchematic(x, y, z, currentState) && y >= minYInclusive && y <= maxYInclusive && realSchematic.inSchematic(x, y, z, currentState); } + @Override + public void reset() { + realSchematic.reset(); + } + @Override public int widthX() { return realSchematic.widthX(); @@ -414,18 +440,18 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } BuilderCalculationContext bcc = new BuilderCalculationContext(); if (!recalc(bcc)) { - if (Baritone.settings().buildInLayers.value && layer < realSchematic.heightY()) { + if (Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < realSchematic.heightY()) { logDirect("Starting layer " + layer); layer++; - return onTick(calcFailed, isSafeToCancel); + return onTick(calcFailed, isSafeToCancel, recursions + 1); } Vec3i repeat = Baritone.settings().buildRepeat.value; int max = Baritone.settings().buildRepeatCount.value; numRepeats++; if (repeat.equals(new Vec3i(0, 0, 0)) || (max != -1 && numRepeats >= max)) { logDirect("Done building"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnBuildFinished.value) { - NotificationHelper.notify("Done building", false); + if (Baritone.settings().notificationOnBuildFinished.value) { + logNotification("Done building", false); } onLostControl(); return null; @@ -433,8 +459,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil // build repeat time layer = 0; origin = new BlockPos(origin).add(repeat); + if (!Baritone.settings().buildRepeatSneaky.value) { + schematic.reset(); + } logDirect("Repeating build in vector " + repeat + ", new origin is " + origin); - return onTick(calcFailed, isSafeToCancel); + return onTick(calcFailed, isSafeToCancel, recursions + 1); } if (Baritone.settings().distanceTrim.value) { trim(); @@ -501,10 +530,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (goal == null) { goal = assemble(bcc, approxPlaceable, true); // we're far away, so assume that we have our whole inventory to recalculate placeable properly if (goal == null) { - if (Baritone.settings().skipFailedLayers.value && Baritone.settings().buildInLayers.value && layer < realSchematic.heightY()) { + if (Baritone.settings().skipFailedLayers.value && Baritone.settings().buildInLayers.value && layer * Baritone.settings().layerHeight.value < realSchematic.heightY()) { logDirect("Skipping layer that I cannot construct! Layer #" + layer); layer++; - return onTick(calcFailed, isSafeToCancel); + return onTick(calcFailed, isSafeToCancel, recursions + 1); } logDirect("Unable to do it. Pausing. resume to resume, cancel to cancel"); paused = true; @@ -589,7 +618,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil continue; } // this is not in render distance - if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))) { + if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ)) + && !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) { // and we've never seen this position be correct // therefore mark as incorrect incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); @@ -818,6 +848,27 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return result; } + public static final Set> orientationProps = + ImmutableSet.of(RotatedPillarBlock.AXIS, HorizontalBlock.HORIZONTAL_FACING, + StairsBlock.FACING, StairsBlock.HALF, StairsBlock.SHAPE, + PaneBlock.NORTH, PaneBlock.EAST, PaneBlock.SOUTH, PaneBlock.WEST, VineBlock.UP, + TrapDoorBlock.OPEN, TrapDoorBlock.HALF + ); + + private boolean sameWithoutOrientation(BlockState first, BlockState second) { + if (first.getBlock() != second.getBlock()) { + return false; + } + ImmutableMap, Comparable> map1 = first.getValues(); + ImmutableMap, Comparable> map2 = second.getValues(); + for (IProperty prop : map1.keySet()) { + if (map1.get(prop) != map2.get(prop) && !orientationProps.contains(prop)) { + return false; + } + } + return true; + } + private boolean valid(BlockState current, BlockState desired, boolean itemVerify) { if (desired == null) { return true; @@ -837,7 +888,16 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) { return true; } - return current.equals(desired); + if (Baritone.settings().buildSkipBlocks.value.contains(desired.getBlock()) && !itemVerify) { + return true; + } + if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) { + return true; + } + if (current.equals(desired)) { + return true; + } + return Baritone.settings().buildIgnoreDirection.value && sameWithoutOrientation(current, desired); } public class BuilderCalculationContext extends CalculationContext { @@ -874,7 +934,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } BlockState sch = getSchematic(x, y, z, current); - if (sch != null) { + if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) { // TODO this can return true even when allowPlace is off.... is that an issue? if (sch.getBlock() instanceof AirBlock) { // we want this to be air, but they're asking if they can place here @@ -908,7 +968,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } BlockState sch = getSchematic(x, y, z, current); - if (sch != null) { + if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) { if (sch.getBlock() instanceof AirBlock) { // it should be air // regardless of current contents, we can break it diff --git a/src/main/java/baritone/process/CustomGoalProcess.java b/src/main/java/baritone/process/CustomGoalProcess.java index f925bec79..ea9ff2092 100644 --- a/src/main/java/baritone/process/CustomGoalProcess.java +++ b/src/main/java/baritone/process/CustomGoalProcess.java @@ -23,7 +23,6 @@ import baritone.api.process.ICustomGoalProcess; import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; import baritone.utils.BaritoneProcessHelper; -import baritone.utils.NotificationHelper; /** * As set by ExampleBaritoneControl or something idk @@ -94,8 +93,8 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC if (Baritone.settings().disconnectOnArrival.value) { ctx.world().sendQuittingDisconnectingPacket(); } - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnPathComplete.value) { - NotificationHelper.notify("Pathing complete", false); + if (Baritone.settings().notificationOnPathComplete.value) { + logNotification("Pathing complete", false); } return new PathingCommand(this.goal, PathingCommandType.CANCEL_AND_SET_GOAL); } diff --git a/src/main/java/baritone/process/ExploreProcess.java b/src/main/java/baritone/process/ExploreProcess.java index c42ece0e5..3664d4188 100644 --- a/src/main/java/baritone/process/ExploreProcess.java +++ b/src/main/java/baritone/process/ExploreProcess.java @@ -29,7 +29,6 @@ import baritone.api.process.PathingCommandType; import baritone.api.utils.MyChunkPos; import baritone.cache.CachedWorld; import baritone.utils.BaritoneProcessHelper; -import baritone.utils.NotificationHelper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -84,8 +83,8 @@ public final class ExploreProcess extends BaritoneProcessHelper implements IExpl public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (calcFailed) { logDirect("Failed"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnExploreFinished.value) { - NotificationHelper.notify("Exploration failed", true); + if (Baritone.settings().notificationOnExploreFinished.value) { + logNotification("Exploration failed", true); } onLostControl(); return null; @@ -93,8 +92,8 @@ public final class ExploreProcess extends BaritoneProcessHelper implements IExpl IChunkFilter filter = calcFilter(); if (!Baritone.settings().disableCompletionCheck.value && filter.countRemain() == 0) { logDirect("Explored all chunks"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnExploreFinished.value) { - NotificationHelper.notify("Explored all chunks", false); + if (Baritone.settings().notificationOnExploreFinished.value) { + logNotification("Explored all chunks", false); } onLostControl(); return null; diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java index 59d10c9ff..e912bb34f 100644 --- a/src/main/java/baritone/process/FarmProcess.java +++ b/src/main/java/baritone/process/FarmProcess.java @@ -31,7 +31,6 @@ import baritone.api.utils.input.Input; import baritone.cache.WorldScanner; import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; -import baritone.utils.NotificationHelper; import net.minecraft.block.*; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; @@ -269,8 +268,8 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro if (calcFailed) { logDirect("Farm failed"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnFarmFail.value) { - NotificationHelper.notify("Farm failed", true); + if (Baritone.settings().notificationOnFarmFail.value) { + logNotification("Farm failed", true); } onLostControl(); return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 444b7f9d0..5db33fc2d 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -32,6 +32,7 @@ import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import net.minecraft.block.Block; import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.util.math.BlockPos; @@ -58,7 +59,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG start = ctx.playerFeet(); blacklist = new ArrayList<>(); arrivalTickCount = 0; - rescan(new ArrayList<>(), new CalculationContext(baritone)); + rescan(new ArrayList<>(), new GetToBlockCalculationContext(false)); } @Override @@ -69,7 +70,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG @Override public synchronized PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (knownLocations == null) { - rescan(new ArrayList<>(), new CalculationContext(baritone)); + rescan(new ArrayList<>(), new GetToBlockCalculationContext(false)); } if (knownLocations.isEmpty()) { if (Baritone.settings().exploreForBlocks.value && !calcFailed) { @@ -78,6 +79,11 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG public boolean isInGoal(int x, int y, int z) { return false; } + + @Override + public double heuristic() { + return Double.NEGATIVE_INFINITY; + } }, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH); } logDirect("No known locations of " + gettingTo + ", canceling GetToBlock"); @@ -103,7 +109,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value; if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain List current = new ArrayList<>(knownLocations); - CalculationContext context = new CalculationContext(baritone, true); + CalculationContext context = new GetToBlockCalculationContext(true); Baritone.getExecutor().execute(() -> rescan(current, context)); } if (goal.isInGoal(ctx.playerFeet()) && goal.isInGoal(baritone.getPathingBehavior().pathStart()) && isSafeToCancel) { @@ -148,6 +154,20 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG return !newBlacklist.isEmpty(); } + // this is to signal to MineProcess that we don't care about the allowBreak setting + // it is NOT to be used to actually calculate a path + public class GetToBlockCalculationContext extends CalculationContext { + + public GetToBlockCalculationContext(boolean forUseOnAnotherThread) { + super(GetToBlockProcess.super.baritone, forUseOnAnotherThread); + } + + @Override + public double breakCostMultiplierAt(int x, int y, int z, BlockState current) { + return 1; + } + } + // safer than direct double comparison from distanceSq private boolean areAdjacent(BlockPos posA, BlockPos posB) { int diffX = Math.abs(posA.getX() - posB.getX()); diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 756c2a17a..39c8f30b0 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -30,8 +30,11 @@ import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.MovementHelper; import baritone.utils.BaritoneProcessHelper; import baritone.utils.BlockStateInterface; -import baritone.utils.NotificationHelper; -import net.minecraft.block.*; +import net.minecraft.block.AirBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.BlockState; +import net.minecraft.block.FallingBlock; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; @@ -86,15 +89,15 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro if (calcFailed) { if (!knownOreLocations.isEmpty() && Baritone.settings().blacklistClosestOnFailure.value) { logDirect("Unable to find any path to " + filter + ", blacklisting presumably unreachable closest instance..."); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnMineFail.value) { - NotificationHelper.notify("Unable to find any path to " + filter + ", blacklisting presumably unreachable closest instance...", true); + if (Baritone.settings().notificationOnMineFail.value) { + logNotification("Unable to find any path to " + filter + ", blacklisting presumably unreachable closest instance...", true); } knownOreLocations.stream().min(Comparator.comparingDouble(ctx.playerFeet()::distanceSq)).ifPresent(blacklist::add); knownOreLocations.removeIf(blacklist::contains); } else { logDirect("Unable to find any path to " + filter + ", canceling mine"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnMineFail.value) { - NotificationHelper.notify("Unable to find any path to " + filter + ", canceling mine", true); + if (Baritone.settings().notificationOnMineFail.value) { + logNotification("Unable to find any path to " + filter + ", canceling mine", true); } cancel(); return null; @@ -186,10 +189,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return new PathingCommand(goal, legit ? PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH : PathingCommandType.REVALIDATE_GOAL_AND_PATH); } // we don't know any ore locations at the moment - if (!legit) { + if (!legit && !Baritone.settings().exploreForBlocks.value) { return null; } - // only in non-Xray mode (aka legit mode) do we do this + // only when we should explore for blocks or are in legit mode we do this int y = Baritone.settings().legitMineYLevel.value; if (branchPoint == null) { /*if (!baritone.getPathingBehavior().isPathing() && playerFeet().y == y) { @@ -209,6 +212,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public boolean isInGoal(int x, int y, int z) { return false; } + @Override + public double heuristic() { + return Double.NEGATIVE_INFINITY; + } }; } return new PathingCommand(branchPointRunaway, PathingCommandType.REVALIDATE_GOAL_AND_PATH); @@ -224,10 +231,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro List dropped = droppedItemsScan(); List locs = searchWorld(context, filter, ORE_LOCATIONS_COUNT, already, blacklist, dropped); locs.addAll(dropped); - if (locs.isEmpty()) { + if (locs.isEmpty() && !Baritone.settings().exploreForBlocks.value) { logDirect("No locations for " + filter + " known, cancelling"); - if (Baritone.settings().desktopNotifications.value && Baritone.settings().notificationOnMineFail.value) { - NotificationHelper.notify("No locations for " + filter + " known, cancelling", true); + if (Baritone.settings().notificationOnMineFail.value) { + logNotification("No locations for " + filter + " known, cancelling", true); } cancel(); return; diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index 6e4e36e23..48062cf8f 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -22,6 +22,9 @@ import baritone.api.utils.IPlayerContext; import baritone.cache.CachedRegion; import baritone.cache.WorldData; import baritone.utils.accessor.IClientChunkProvider; +import baritone.utils.pathing.BetterWorldBorder; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -46,6 +49,7 @@ public class BlockStateInterface { protected final IBlockReader world; public final BlockPos.MutableBlockPos isPassableBlockPos; public final IBlockReader access; + public final BetterWorldBorder worldBorder; private Chunk prev = null; private CachedRegion prevCached = null; @@ -64,6 +68,7 @@ public class BlockStateInterface { public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) { this.world = world; + this.worldBorder = new BetterWorldBorder(world.getWorldBorder()); this.worldData = worldData; if (copyLoadedChunks) { this.provider = ((IClientChunkProvider) world.getChunkProvider()).createThreadSafeCopy(); diff --git a/src/main/java/baritone/utils/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index 48fc21b6b..d599ea259 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -219,8 +219,14 @@ public final class PathRenderer implements IRenderer, Helper { double minX, maxX; double minZ, maxZ; double minY, maxY; - double y1, y2; - double y = MathHelper.cos((float) (((float) ((System.nanoTime() / 100000L) % 20000L)) / 20000F * Math.PI * 2)); + double y, y1, y2; + if (!settings.renderGoalAnimated.value) { + // y = 1 causes rendering issues when the player is at the same y as the top of a block for some reason + y = 0.999F; + } + else { + y = MathHelper.cos((float) (((float) ((System.nanoTime() / 100000L) % 20000L)) / 20000F * Math.PI * 2)); + } if (goal instanceof IGoalRenderPos) { BlockPos goalPos = ((IGoalRenderPos) goal).getGoalPos(); minX = goalPos.getX() + 0.002 - renderPosX; @@ -254,9 +260,9 @@ public final class PathRenderer implements IRenderer, Helper { goalPos.getX() - renderPosX, -renderPosY, goalPos.getZ() - renderPosZ, - partialTicks, + settings.renderGoalAnimated.value ? partialTicks : 0, 1.0, - player.world.getGameTime(), + settings.renderGoalAnimated.value ? player.world.getGameTime() : 0, 0, 256, color.getColorComponents(null), diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index 06cd406ad..a2f6e32f6 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -24,6 +24,7 @@ import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.Enchantments; import net.minecraft.item.ItemStack; +import net.minecraft.item.SwordItem; import net.minecraft.item.ToolItem; import net.minecraft.potion.Effects; @@ -106,7 +107,7 @@ public class ToolSet { If we actually want know what efficiency our held item has instead of the best one possible, this lets us make pathing depend on the actual tool to be used (if auto tool is disabled) */ - if (Baritone.settings().disableAutoTool.value && pathingCalculation) { + if (!Baritone.settings().autoTool.value && pathingCalculation) { return player.inventory.currentItem; } @@ -117,6 +118,13 @@ public class ToolSet { BlockState blockState = b.getDefaultState(); for (int i = 0; i < 9; i++) { ItemStack itemStack = player.inventory.getStackInSlot(i); + if (!Baritone.settings().useSwordToMine.value && itemStack.getItem() instanceof SwordItem) { + continue; + } + + if (Baritone.settings().itemSaver.value && (itemStack.getDamage() + Baritone.settings().itemSaverThreshold.value) >= itemStack.getMaxDamage() && itemStack.getMaxDamage() > 1) { + continue; + } double speed = calculateSpeedVsBlock(itemStack, blockState); boolean silkTouch = hasSilkTouch(itemStack); if (speed > highestSpeed) { @@ -150,7 +158,7 @@ public class ToolSet { } private double avoidanceMultiplier(Block b) { - return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? 0.1 : 1; + return Baritone.settings().blocksToAvoidBreaking.value.contains(b) ? Baritone.settings().avoidBreakingMultiplier.value : 1; } /** diff --git a/src/main/java/baritone/utils/schematic/SelectionSchematic.java b/src/main/java/baritone/utils/schematic/SelectionSchematic.java new file mode 100644 index 000000000..93a09c5bc --- /dev/null +++ b/src/main/java/baritone/utils/schematic/SelectionSchematic.java @@ -0,0 +1,53 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils.schematic; + +import baritone.api.schematic.ISchematic; +import baritone.api.schematic.MaskSchematic; +import baritone.api.selection.ISelection; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.Vec3i; + +import java.util.stream.Stream; + +public class SelectionSchematic extends MaskSchematic { + + private final ISelection[] selections; + + public SelectionSchematic(ISchematic schematic, Vec3i origin, ISelection[] selections) { + super(schematic); + this.selections = Stream.of(selections).map( + sel -> sel + .shift(Direction.WEST, origin.getX()) + .shift(Direction.DOWN, origin.getY()) + .shift(Direction.NORTH, origin.getZ())) + .toArray(ISelection[]::new); + } + + @Override + protected boolean partOfMask(int x, int y, int z, BlockState currentState) { + for (ISelection selection : selections) { + if (x >= selection.min().x && y >= selection.min().y && z >= selection.min().z + && x <= selection.max().x && y <= selection.max().y && z <= selection.max().z) { + return true; + } + } + return false; + } +}