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..69317376f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,12 @@ classes/ *.iws /logs/ +# Eclipse Files +.classpath +.project +.settings/ +baritone_Client.launch + # Copyright Files !/.idea/copyright/Baritone.xml !/.idea/copyright/profiles_settings.xml 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..85f3bf84e 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,63 @@ # 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 +

-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 +

+ +

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

+ +

+ 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.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. +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)**. 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 through 1.16.5. 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. diff --git a/SETUP.md b/SETUP.md index e7ef6c274..7a43faa62 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.2 or 1.16.4 or 1.16.5 (LOL) -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). @@ -32,11 +32,6 @@ If another one of your Forge mods has a Baritone integration, you want `baritone - **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. - **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`. - ## Build it yourself - Clone or download Baritone diff --git a/USAGE.md b/USAGE.md index 35aa90a7b..f896ad012 100644 --- a/USAGE.md +++ b/USAGE.md @@ -47,7 +47,7 @@ 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. diff --git a/build.gradle b/build.gradle index 5a985962e..4e2a6b161 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..c92a371eb 100644 --- a/scripts/proguard.pro +++ b/scripts/proguard.pro @@ -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 9e02d6f17..20566f54b 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.client.Minecraft; import net.minecraft.init.Blocks; @@ -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 @@ -205,6 +208,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 *

@@ -576,6 +602,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 */ @@ -645,7 +677,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. */ @@ -700,6 +732,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. @@ -760,7 +802,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); @@ -812,6 +854,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 @@ -823,6 +870,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 */ @@ -833,6 +885,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 *

@@ -941,6 +1000,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); @@ -1027,6 +1087,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 */ @@ -1117,6 +1191,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/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 b48a029ad..e93f47ac0 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 2f119de1b..234f1d4fe 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 049aef7f5..46e6cb6b3 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.state.IBlockState; -import net.minecraft.init.Blocks; import java.util.List; @@ -44,8 +43,6 @@ public class FillSchematic extends AbstractSchematic { public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { if (bom.matches(current)) { return current; - } else if (current.getBlock() != Blocks.AIR) { - return Blocks.AIR.getDefaultState(); } for (IBlockState 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 88cfc8999..deb811828 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 { */ IBlockState desiredState(int x, int y, int z, IBlockState 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 f064435e0..f8cd6656b 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, IBlockState 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..e8fd1fced --- /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.Block; +import net.minecraft.block.BlockAir; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +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, IBlockState currentState) { + return schematic.inSchematic(x, y, z, currentState); + } + + @Override + public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) { + IBlockState 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 BlockAir)) {// 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 BlockAir) { + return current.getBlock() instanceof BlockAir ? current : Blocks.AIR.getDefaultState(); // can always "place" air + } + for (IBlockState placeable : approxPlaceable) { + if (substitute.equals(placeable.getBlock())) { + return withBlock(desired, placeable.getBlock()); + } + } + } + return substitutes.get(0).getDefaultState(); + } + + private IBlockState withBlock(IBlockState state, Block block) { + if (blockStateCache.containsKey(state) && blockStateCache.get(state).containsKey(block)) { + return blockStateCache.get(state).get(block); + } + Collection> properties = state.getBlock().getStateContainer().getProperties(); + IBlockState 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 > IBlockState copySingleProp(IBlockState fromState, IBlockState 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 f92af0574..c975d6f28 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.TextComponentString; @@ -71,7 +70,7 @@ public interface Helper { * @param message The message to display in the popup */ default void logToast(ITextComponent title, ITextComponent message) { - mc.addScheduledTask(() -> BaritoneToast.addOrUpdate(mc.getToastGui(), title, message, BaritoneAPI.getSettings().toastTimer.value)); + mc.addScheduledTask(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message)); } /** @@ -93,6 +92,48 @@ public interface Helper { logToast(Helper.getPrefix(), new TextComponentString(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.addScheduledTask(() -> 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 ce281665f..44ecce0cb 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 a84beef7b..3c68ee5a9 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/behavior/InventoryBehavior.java b/src/main/java/baritone/behavior/InventoryBehavior.java index d45893e4d..50544a301 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; @@ -112,6 +113,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) { @@ -149,6 +153,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) { EntityPlayerSP p = ctx.player(); NonNullList inv = p.inventory.mainInventory; for (int i = 0; i < 9; i++) { @@ -181,6 +189,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 index 66ab10f31..b7d31223a 100644 --- a/src/main/java/baritone/behavior/MemoryBehavior.java +++ b/src/main/java/baritone/behavior/MemoryBehavior.java @@ -25,6 +25,7 @@ import baritone.api.event.events.PlayerUpdateEvent; import baritone.api.event.events.TickEvent; import baritone.api.event.events.type.EventState; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.Helper; import baritone.cache.ContainerMemory; import baritone.utils.BlockStateInterface; import net.minecraft.block.Block; @@ -40,13 +41,20 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityLockable; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.event.ClickEvent; +import net.minecraft.util.text.event.HoverEvent; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; + /** * doesn't work for horse inventories :^) * @@ -166,7 +174,26 @@ public final class MemoryBehavior extends Behavior { @Override public void onPlayerDeath() { - baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet())); + Waypoint deathWaypoint = new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet()); + baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(deathWaypoint); + ITextComponent component = new TextComponentString("Death position saved."); + component.getStyle() + .setColor(TextFormatting.WHITE) + .setHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_TEXT, + new TextComponentString("Click to goto death") + )) + .setClickEvent(new ClickEvent( + ClickEvent.Action.RUN_COMMAND, + String.format( + "%s%s goto %s @ %d", + FORCE_COMMAND_PREFIX, + "wp", + deathWaypoint.getTag().getName(), + deathWaypoint.getCreationTimestamp() + ) + )); + Helper.HELPER.logDirect(component); } 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 cc4fda72e..c597dcafa 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.x << 4, y, z + chunk.z << 4)); + Vec3d flow = state.getFluidState().getFlow(chunk.getWorld(), new BlockPos(x + (chunk.x << 4), y, z + (chunk.z << 4))); if (flow.x != 0.0 || flow.z != 0.0) { return PathingBlockType.WATER; } diff --git a/src/main/java/baritone/command/ExampleBaritoneControl.java b/src/main/java/baritone/command/ExampleBaritoneControl.java index 66d5989ed..a4722a2ff 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..17f338046 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), diff --git a/src/main/java/baritone/command/defaults/ETACommand.java b/src/main/java/baritone/command/defaults/ETACommand.java new file mode 100644 index 000000000..3c16bd113 --- /dev/null +++ b/src/main/java/baritone/command/defaults/ETACommand.java @@ -0,0 +1,78 @@ +/* + * 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.command.defaults; + +import baritone.api.IBaritone; +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.exception.CommandException; +import baritone.api.command.exception.CommandInvalidStateException; +import baritone.api.command.argument.IArgConsumer; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +public class ETACommand extends Command { + + public ETACommand(IBaritone baritone) { + super(baritone, "eta"); + } + + @Override + public void execute(String label, IArgConsumer args) throws CommandException { + args.requireMax(0); + 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 + public Stream tabComplete(String label, IArgConsumer args) { + return Stream.empty(); + } + + @Override + public String getShortDesc() { + return "View the current ETA"; + } + + @Override + public List getLongDesc() { + return Arrays.asList( + "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:", + "> eta - View ETA, if present" + ); + } +} diff --git a/src/main/java/baritone/command/defaults/FollowCommand.java b/src/main/java/baritone/command/defaults/FollowCommand.java index 88f3bb150..75af0ad03 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); } } @@ -74,12 +75,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(IRegistry.ENTITY_TYPE::getKey) .map(Objects::requireNonNull) @@ -156,4 +159,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 0eab8a9a9..659a31835 100644 --- a/src/main/java/baritone/command/defaults/SelCommand.java +++ b/src/main/java/baritone/command/defaults/SelCommand.java @@ -37,6 +37,9 @@ 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.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; @@ -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(); + IBlockState[][][] blockstates = new IBlockState[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 19f1243b2..e9e35d413 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 TextComponentString(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/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/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index 2b49edbcc..a2f4865f5 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -441,7 +441,7 @@ public interface MovementHelper extends ActionCosts, Helper { * @param ts previously calculated ToolSet */ static void switchToBestToolFor(IPlayerContext ctx, IBlockState 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 6a894e7f8..4f1e7d2ea 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 IBlockState 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 IBlockState 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; - IBlockState 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; + IBlockState 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 e50b710ae..3847215ff 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,9 +40,9 @@ 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 it.unimi.dsi.fastutil.longs.LongOpenHashSet; @@ -88,6 +89,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(); @@ -139,6 +143,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; } @@ -149,10 +158,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"); @@ -360,6 +374,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; @@ -381,9 +402,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() { @@ -397,6 +418,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(); @@ -415,18 +441,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; @@ -434,8 +460,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(); @@ -502,10 +531,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; @@ -590,7 +619,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)); @@ -838,6 +868,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!(current.getBlock() instanceof BlockAir) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) { return true; } + 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; + } return current.equals(desired); } @@ -875,7 +911,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } IBlockState 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 BlockAir) { // we want this to be air, but they're asking if they can place here @@ -909,7 +945,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } IBlockState sch = getSchematic(x, y, z, current); - if (sch != null) { + if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) { if (sch.getBlock() instanceof BlockAir) { // 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 7b70188a4..12a21531f 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.block.state.IBlockState; import net.minecraft.entity.Entity; @@ -270,8 +269,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 88cacca0c..6280e39bd 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -30,6 +30,7 @@ import baritone.api.utils.input.Input; import baritone.pathing.movement.CalculationContext; import baritone.utils.BaritoneProcessHelper; import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; import net.minecraft.inventory.ContainerPlayer; import net.minecraft.util.math.BlockPos; @@ -57,7 +58,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 @@ -68,7 +69,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) { @@ -77,6 +78,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"); @@ -102,7 +108,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) { @@ -147,6 +153,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, IBlockState 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 ea35fd566..1ec47cd92 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -30,7 +30,6 @@ 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.Block; import net.minecraft.block.BlockAir; import net.minecraft.block.BlockFalling; @@ -89,15 +88,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.player()::getDistanceSq)).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; @@ -188,10 +187,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) { @@ -211,6 +210,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); @@ -226,10 +229,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/PathRenderer.java b/src/main/java/baritone/utils/PathRenderer.java index b2a87b02a..f09f99939 100644 --- a/src/main/java/baritone/utils/PathRenderer.java +++ b/src/main/java/baritone/utils/PathRenderer.java @@ -207,8 +207,14 @@ public final class PathRenderer implements IRenderer { 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; @@ -244,9 +250,9 @@ public final class PathRenderer implements IRenderer { 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 43cc8c080..79a06db58 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -25,6 +25,7 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.init.Enchantments; import net.minecraft.init.MobEffects; import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; import net.minecraft.item.ItemTool; import java.util.HashMap; @@ -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 { IBlockState blockState = b.getDefaultState(); for (int i = 0; i < 9; i++) { ItemStack itemStack = player.inventory.getStackInSlot(i); + if (!Baritone.settings().useSwordToMine.value && itemStack.getItem() instanceof ItemSword) { + 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) { 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..243a3d4d0 --- /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.state.IBlockState; +import net.minecraft.util.EnumFacing; +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(EnumFacing.WEST, origin.getX()) + .shift(EnumFacing.DOWN, origin.getY()) + .shift(EnumFacing.NORTH, origin.getZ())) + .toArray(ISelection[]::new); + } + + @Override + protected boolean partOfMask(int x, int y, int z, IBlockState 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; + } +}