diff --git a/.github/workflows/gradle_build.yml b/.github/workflows/gradle_build.yml index 08e9ab1d3..56c11e193 100644 --- a/.github/workflows/gradle_build.yml +++ b/.github/workflows/gradle_build.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' @@ -28,16 +28,16 @@ jobs: run: chmod +x gradlew - name: Build with Gradle - run: ./gradlew build -Pmod_version="$(git describe --always --tags | cut -c2-)" + run: ./gradlew build -Pmod_version="$(git describe --always --tags --first-parent | cut -c2-)" - name: Archive Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Artifacts path: dist/ - name: Archive mapping.txt - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Mappings path: mapping/ diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 34d52e54c..04b26b422 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' diff --git a/Dockerfile b/Dockerfile index 9023e2020..8a00fc3da 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ RUN apt update -y RUN apt install \ openjdk-17-jdk \ + git \ --assume-yes COPY . /code diff --git a/README.md b/README.md index 3f2923f92..fa5a624e4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Minecraft Minecraft Minecraft + Minecraft

@@ -63,11 +64,14 @@ Baritone is the pathfinding system used in [Impact](https://impactclient.net/) s | [1.12.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.2.19/baritone-api-forge-1.2.19.jar) | | | [1.16.5 Forge](https://github.com/cabaletta/baritone/releases/download/v1.6.5/baritone-api-forge-1.6.5.jar) | [1.16.5 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.6.5/baritone-api-fabric-1.6.5.jar) | | [1.17.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-forge-1.7.3.jar) | [1.17.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-fabric-1.7.3.jar) | -| [1.18.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.8.5/baritone-api-forge-1.8.5.jar) | [1.18.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.8.5/baritone-api-fabric-1.8.5.jar) | +| [1.18.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.8.6/baritone-api-forge-1.8.6.jar) | [1.18.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.8.6/baritone-api-fabric-1.8.6.jar) | | [1.19.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-forge-1.9.4.jar) | [1.19.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-fabric-1.9.4.jar) | | [1.19.3 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-forge-1.9.1.jar) | [1.19.3 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-fabric-1.9.1.jar) | | [1.19.4 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-forge-1.9.3.jar) | [1.19.4 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-fabric-1.9.3.jar) | | [1.20.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-forge-1.10.1.jar) | [1.20.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-fabric-1.10.1.jar) | +| [1.20.3 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.2/baritone-api-forge-1.10.2.jar) | [1.20.3 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.2/baritone-api-fabric-1.10.2.jar) | +| [1.20.4 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.2/baritone-api-forge-1.10.2.jar) | [1.20.4 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.2/baritone-api-fabric-1.10.2.jar) | +| [1.21.3 Forge](https://github.com/cabaletta/baritone/releases/download/v1.11.1/baritone-api-forge-1.11.1.jar) | [1.21.3 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.11.1/baritone-api-fabric-1.11.1.jar) | **Message for 2b2t players looking for 1.19/1.20 Baritone** If you like, please try the beta for Baritone Elytra for 2b2t, find it in #announcements of [the Baritone discord](http://discord.gg/s6fRBAUpmr). It supports 1.19.4 and 1.20.1, Forge or Fabric. If you have to see it to believe it, watch [this YouTube video](https://youtu.be/NnSlQi-68eQ). diff --git a/SETUP.md b/SETUP.md index 1daeb9f89..1bf6e5dbd 100644 --- a/SETUP.md +++ b/SETUP.md @@ -1,78 +1,87 @@ # Installation -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 or the [1.16.5](https://www.dropbox.com/s/i6f292o2i7o9acp/1.16.5-Baritone.zip?dl=1) version. +The easiest way to install Baritone is to install it as Forge/Neoforge/Fabric mod, but if you know how you can also use with a custom `version.json` +(Examples: [1.14.4](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1), [1.15.2](https://www.dropbox.com/s/8rx6f0kts9hvd4f/1.15.2-Baritone.zip?dl=1), [1.16.5](https://www.dropbox.com/s/i6f292o2i7o9acp/1.16.5-Baritone.zip?dl=1)). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. ## Prebuilt official releases -These releases are not always completely up to date with latest features, and are only released from `master`. (so if you want `backfill-2` branch for example, you'll have to build it yourself) +Releases are made rarely and are not always up to date with the latest features and bug fixes. 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.4.* is for 1.14.4, v1.5.* is for 1.15.2, v1.6.* is for 1.16.5, v1.7.* is for 1.17.1, v1.8.* is for 1.18.1 +The mapping between major Minecraft versions and major Baritone versions is as follows +| Minecraft version | 1.12 | 1.13 | 1.14 | 1.15 | 1.16 | 1.17 | 1.18 | 1.19 | 1.20 | 1.21 | +|-------------------|------|------|------|------|------|------|------|------|-------|-------| +| Baritone version | v1.2 | v1.3 | v1.4 | v1.5 | v1.6 | v1.7 | v1.8 | v1.9 | v1.10 | v1.11 | 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). +The build is fully deterministic and reproducible, and you can verify that 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). ## Artifacts -Building Baritone will result in 5 artifacts created in the ``dist`` directory. These are the same as the artifacts created in the [releases](https://github.com/cabaletta/baritone/releases). +Building Baritone will create the final artifacts in the ``dist`` directory. These are the same as the artifacts created in the [releases](https://github.com/cabaletta/baritone/releases). -**The Forge and Fabric releases can simply be added as a Forge/Fabric mods.** +**The Forge, NeoForge and Fabric releases can simply be added as a Forge/Neoforge/Fabric mods.** -If another one of your Forge mods has a Baritone integration, you want `baritone-api-forge-VERSION.jar`. Otherwise, you want `baritone-standalone-forge-VERSION.jar` +If another one of your other mods has a Baritone integration, you want `baritone-api-*-VERSION.jar`. +If you want to report a bug and spare us some effort, you want `baritone-unoptimized-*-VERSION.jar`. +Otherwise, you want `baritone-standalone-*-VERSION.jar` +Here's what the various qualifiers mean - **API**: Only the non-api packages are obfuscated. This should be used in environments where other mods would like to use Baritone's features. -- **Forge/Fabric API**: Same as API, but packaged for Forge/Fabric. This should be used where another mod has a Baritone integration. -- **Standalone**: Everything is obfuscated. This should be used in environments where there are no other mods present that would like to use Baritone's features. -- **Forge/Fabric Standalone**: Same as Standalone, but packaged for Forge/Fabric. This should be used when Baritone is your only Forge/Fabric mod, or none of your other Forge/Fabric mods integrate with Baritone. -- **Unoptimized**: Nothing is obfuscated. This shouldn't be used ever in production. -- **Forge/Fabric Unoptimized**: Same as Unoptimized, but packaged for Forge/Fabric. +- **Standalone**: Everything is obfuscated. Other mods cannot use Baritone, but you get a bit of extra performance. +- **Unoptimized**: Nothing is obfuscated. This shouldn't be used in production, but is really helpful for crash reports. + +- **No loader**: Loadable as a launchwrapper tweaker against vanilla Minecraft using a custom `version.json`. +- **Forge/Neoforge/Fabric**: Loadable as a standard mod using the respective loader. The fabric build may or may not work on Quilt. + +If you build from source you will also find mapping files in the `dist` directory. These contain the renamings done by ProGuard and are useful if you want to read obfuscated stack traces. ## Build it yourself - Clone or download Baritone ![Image](https://i.imgur.com/kbqBtoN.png) - - If you choose to download, make sure you extract the ZIP archive. + - If you choose to download, make sure you download the correct branch and extract the ZIP archive. - Follow one of the instruction sets below, based on your preference ## Command Line On Mac OSX and Linux, use `./gradlew` instead of `gradlew`. -If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16+ for 1.17.1, and JDK 17+ for 1.18.1. - -To check which java you are using do -`java -version` in a command prompt or terminal. -If you are using anything above OpenJDK 8 for 1.12.2-1.16.5, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes. +The recommended Java versions by Minecraft version are +| Minecraft version | Java version | +|-------------------------------|---------------| +| 1.12.2 - 1.16.5 | 8 | +| 1.17.1 | 16 | +| 1.18.2 - 1.20.4 | 17 | +| 1.20.5 - 1.21.4 | 21 | Download java: https://adoptium.net/ -#### macOS guide -In order to get JDK 8, Try running the following command: -`% /usr/libexec/java_home -V` -If it doesn't work try this guide: https://stackoverflow.com/questions/46513639/how-to-downgrade-java-from-9-to-8-on-a-macos-eclipse-is-not-running-with-java-9 -If you see something like - -`% 1.8.0_VERSION, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_VERSION.jdk/Contents/Home` - -in the list then you've got JDK 8 installed. -In order to get JDK 8 running in the **current terminal window** you will have to run this command: - -`% export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)` - -To add OpenJDK 8 to your PATH add the export line to the end of your `.zshrc / .bashrc` if you want it to apply to each new terminal. If you're using bash change the .bachrc and if you're using zsh change the .zshrc +To check which java version you are using do `java -version` in a command prompt or terminal. ### Building Baritone These tasks depend on the minecraft version, but are (for the most part) standard for building mods. -for more details, see [the build ci action](/.github/workflows/gradle_build.yml) +For more details, see [the build ci action](/.github/workflows/gradle_build.yml) of the branch you want to build. + +For most branches `gradlew build` should build everything, but there are exceptions and this file might be out of date. + +More specifically, on older branches the setup used to be that `gradlew build` builds the tweaker jar +and `gradlew build -Pbaritone.forge_build` / `gradlew build -Pbaritone.fabric_build` are needed to build +for Forge/Fabric instead. And you might have to run `setupDecompWorkspace` first. ## IntelliJ - Open the project in IntelliJ as a Gradle project - Refresh the Gradle project (or, to be safe, just restart IntelliJ) -- depending on the minecraft version, you may need to run `setupDecompWorkspace` or `genIntellijRuns` in order to get everything working \ No newline at end of file +- Depending on the minecraft version, you may need to run `setupDecompWorkspace` or `genIntellijRuns` in order to get everything working + +## Github Actions +Most branches have a CI workflow at `.github/workflows/gradle_build.yml`. If you fork this repository and enable actions for your fork +you can push a dummy commit to trigger it and have GitHub build Baritone for you. + +If the commit you want to build is less than 90 days old, you can also find the corresponding workflow run in +[this list](https://github.com/cabaletta/baritone/actions/workflows/gradle_build.yml) and download the artifacts from there. diff --git a/build.gradle b/build.gradle index 71520578f..3dcd71179 100755 --- a/build.gradle +++ b/build.gradle @@ -21,17 +21,29 @@ allprojects { apply plugin: "maven-publish" archivesBaseName = rootProject.archives_base_name - def vers = 'git describe --always --tags --dirty'.execute().text.trim() + + def vers = "" + try { + vers = 'git describe --always --tags --first-parent --dirty'.execute().text.trim() + } catch (Exception e) { + println "Version detection failed: " + e + } if (!vers.startsWith("v")) { - println "git doesn't appear to be installed!" println "using version number: " + rootProject.mod_version version = rootProject.mod_version } else { version = vers.substring(1) + println "Detected version " + version } group = rootProject.maven_group - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = targetCompatibility = JavaVersion.toVersion(project.java_version) + + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(sourceCompatibility.majorVersion.toInteger())) + } + } repositories { maven { @@ -66,32 +78,35 @@ allprojects { } dependencies { - minecraft "net.minecraft:minecraft:${rootProject.minecraft_version}" - // The following line declares the mojmap mappings, you may use other mappings as well - mappings "net.fabricmc:intermediary:${rootProject.minecraft_version}:v2" - mappings "net.minecraft:minecraft:${rootProject.minecraft_version}:client-mappings" - mappings "org.parchmentmc.data:parchment-1.19.2:2022.11.27@zip" + compileOnly "org.spongepowered:mixin:${project.mixin_version}" + compileOnly "org.ow2.asm:asm:${project.asm_version}" - implementation "org.spongepowered:mixin:0.8.5" - implementation "org.ow2.asm:asm:9.3" - // The following line declares the yarn mappings you may select this one as well. - // mappings "net.fabricmc:yarn:1.17.1+build.32:v2" - //launchImplementation('dev.babbaj:nether-pathfinder:1.3.0') - implementation 'dev.babbaj:nether-pathfinder:1.4.1' + implementation "dev.babbaj:nether-pathfinder:${project.nether_pathfinder_version}" + } + + unimined.minecraft(sourceSets.main, true) { + version rootProject.minecraft_version + + mappings { + intermediary() + mojmap() + parchment("2023.06.26") + } } tasks.withType(JavaCompile).configureEach { it.options.encoding = "UTF-8" - def targetVersion = 17 + def targetVersion = project.java_version.toInteger() if (JavaVersion.current().isJava9Compatible()) { it.options.release = targetVersion } } } -minecraft { +unimined.minecraft { runs.off = true + defaultRemapJar = false } archivesBaseName = archivesBaseName + "-common" @@ -131,10 +146,6 @@ jar { from sourceSets.main.output, sourceSets.launch.output, sourceSets.api.output } -remapJar { - target = "mojmap" -} - javadoc { options.addStringOption('Xwerror', '-quiet') // makes the build fail on travis when there is a javadoc error options.linkSource true diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index d0ba8faf5..d894aeec2 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -29,12 +29,16 @@ repositories { name = 'FabricMaven' url = 'https://maven.fabricmc.net/' } + maven { + name = 'NeoForgedMaven' + url = 'https://maven.neoforged.net/' + } mavenCentral() } dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.9.0' - implementation group: 'commons-io', name: 'commons-io', version: '2.6' + implementation group: 'commons-io', name: 'commons-io', version: '2.7' - implementation group: 'xyz.wagyourtail.unimined', name: 'xyz.wagyourtail.unimined.gradle.plugin', version: '0.4.10' + implementation group: 'xyz.wagyourtail.unimined', name: 'xyz.wagyourtail.unimined.gradle.plugin', version: '1.0.5' } \ No newline at end of file diff --git a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java index 2dad551f2..f27df9aaa 100644 --- a/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java +++ b/buildSrc/src/main/java/baritone/gradle/task/BaritoneGradleTask.java @@ -36,8 +36,8 @@ import java.nio.file.Paths; class BaritoneGradleTask extends DefaultTask { protected static final String - PROGUARD_ZIP = "proguard.zip", - PROGUARD_JAR = "proguard.jar", + PROGUARD_ZIP = "proguard-%s.zip", + PROGUARD_JAR = "proguard-%s.jar", PROGUARD_CONFIG_TEMPLATE = "scripts/proguard.pro", PROGUARD_CONFIG_DEST = "template.pro", PROGUARD_API_CONFIG = "api.pro", diff --git a/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java index 6a1186cfc..d5e05a19c 100644 --- a/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java +++ b/buildSrc/src/main/java/baritone/gradle/task/ProguardTask.java @@ -20,14 +20,17 @@ package baritone.gradle.task; import baritone.gradle.util.Determinizer; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskCollection; import org.gradle.api.tasks.compile.ForkOptions; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.internal.jvm.Jvm; -import xyz.wagyourtail.unimined.api.Constants; -import xyz.wagyourtail.unimined.api.minecraft.EnvType; -import xyz.wagyourtail.unimined.api.minecraft.MinecraftProvider; +import org.gradle.jvm.toolchain.JavaLanguageVersion; +import org.gradle.jvm.toolchain.JavaLauncher; +import org.gradle.jvm.toolchain.JavaToolchainService; +import xyz.wagyourtail.unimined.api.UniminedExtension; +import xyz.wagyourtail.unimined.api.minecraft.MinecraftConfig; import java.io.*; import java.net.URL; @@ -35,7 +38,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.stream.Stream; import java.util.zip.ZipEntry; @@ -48,23 +50,14 @@ import java.util.zip.ZipFile; public class ProguardTask extends BaritoneGradleTask { @Input - private String url; + private String proguardVersion; - public String getUrl() { - return url; - } - - @Input - private String extract; - - public String getExtract() { - return extract; + public String getProguardVersion() { + return proguardVersion; } private List requiredLibraries; - private File pathfinder; - @TaskAction protected void exec() throws Exception { super.doFirst(); @@ -74,21 +67,23 @@ public class ProguardTask extends BaritoneGradleTask { downloadProguard(); extractProguard(); generateConfigs(); - pathfinder = acquireDependencies().filter(file -> file.getName().contains("nether-pathfinder")).findAny().get(); processArtifact(); proguardApi(); proguardStandalone(); cleanup(); } - MinecraftProvider provider = this.getProject().getExtensions().getByType(MinecraftProvider.class); + UniminedExtension ext = getProject().getExtensions().getByType(UniminedExtension.class); + SourceSetContainer sourceSets = getProject().getExtensions().getByType(SourceSetContainer.class); private File getMcJar() { - return provider.getMinecraftWithMapping(EnvType.COMBINED, provider.getMcPatcher().getProdNamespace(), provider.getMcPatcher().getProdNamespace()).toFile(); + MinecraftConfig mcc = ext.getMinecrafts().get(sourceSets.getByName("main")); + return mcc.getMinecraft(mcc.getMcPatcher().getProdNamespace(), mcc.getMcPatcher().getProdNamespace()).toFile(); } private boolean isMcJar(File f) { - return this.getProject().getConfigurations().getByName(Constants.MINECRAFT_COMBINED_PROVIDER).getFiles().contains(f); + MinecraftConfig mcc = ext.getMinecrafts().get(sourceSets.getByName("main")); + return mcc.isMinecraftJar(f.toPath()); } private void processArtifact() throws Exception { @@ -96,102 +91,37 @@ public class ProguardTask extends BaritoneGradleTask { Files.delete(this.artifactUnoptimizedPath); } - Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString(), Arrays.asList(pathfinder), false); + Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString(), List.of(), false); } private void downloadProguard() throws Exception { - Path proguardZip = getTemporaryFile(PROGUARD_ZIP); + Path proguardZip = getTemporaryFile(String.format(PROGUARD_ZIP, proguardVersion)); if (!Files.exists(proguardZip)) { - write(new URL(this.url).openStream(), proguardZip); + write(new URL(String.format("https://github.com/Guardsquare/proguard/releases/download/v%s/proguard-%s.zip", proguardVersion, proguardVersion)).openStream(), proguardZip); } } private void extractProguard() throws Exception { - Path proguardJar = getTemporaryFile(PROGUARD_JAR); + Path proguardJar = getTemporaryFile(String.format(PROGUARD_JAR, proguardVersion)); if (!Files.exists(proguardJar)) { - ZipFile zipFile = new ZipFile(getTemporaryFile(PROGUARD_ZIP).toFile()); - ZipEntry zipJarEntry = zipFile.getEntry(this.extract); + ZipFile zipFile = new ZipFile(getTemporaryFile(String.format(PROGUARD_ZIP, proguardVersion)).toFile()); + ZipEntry zipJarEntry = zipFile.getEntry(String.format("proguard-%s/lib/proguard.jar", proguardVersion)); write(zipFile.getInputStream(zipJarEntry), proguardJar); zipFile.close(); } } - private String getJavaBinPathForProguard() throws Exception { - String path; - try { - path = findJavaPathByGradleConfig(); - if (path != null) return path; - } catch (Exception ex) { - System.err.println("Unable to find java by javaCompile options"); - ex.printStackTrace(); + private JavaLauncher getJavaLauncherForProguard() { + var toolchains = getProject().getExtensions().getByType(JavaToolchainService.class); + var toolchain = toolchains.launcherFor((spec) -> { + spec.getLanguageVersion().set(JavaLanguageVersion.of(getProject().findProperty("java_version").toString())); + }).getOrNull(); + + if (toolchain == null) { + throw new IllegalStateException("Java toolchain not found"); } - path = findJavaByGradleCurrentRuntime(); - if (path != null) return path; - - try { - path = findJavaByJavaHome(); - if (path != null) return path; - } catch (Exception ex) { - System.err.println("Unable to find java by JAVA_HOME"); - ex.printStackTrace(); - } - - throw new Exception("Unable to find java to determine ProGuard libraryjars. Please specify forkOptions.executable in javaCompile," + - " JAVA_HOME environment variable, or make sure to run Gradle with the correct JDK (a v1.8 only)"); - } - - private String findJavaByGradleCurrentRuntime() { - String path = Jvm.current().getJavaExecutable().getAbsolutePath(); - System.out.println("Using Gradle's runtime Java for ProGuard"); - return path; - } - - private String findJavaByJavaHome() { - final String javaHomeEnv = System.getenv("JAVA_HOME"); - if (javaHomeEnv != null) { - String path = Jvm.forHome(new File(javaHomeEnv)).getJavaExecutable().getAbsolutePath(); - System.out.println("Detected Java path by JAVA_HOME"); - return path; - } - return null; - } - - private String findJavaPathByGradleConfig() { - final TaskCollection javaCompiles = super.getProject().getTasks().withType(JavaCompile.class); - - final JavaCompile compileTask = javaCompiles.iterator().next(); - final ForkOptions forkOptions = compileTask.getOptions().getForkOptions(); - - if (forkOptions != null) { - String javacPath = forkOptions.getExecutable(); - if (javacPath != null) { - File javacFile = new File(javacPath); - if (javacFile.exists()) { - File[] maybeJava = javacFile.getParentFile().listFiles((dir, name) -> name.equals("java")); - if (maybeJava != null && maybeJava.length > 0) { - String path = maybeJava[0].getAbsolutePath(); - System.out.println("Detected Java path by forkOptions"); - return path; - } - } - } - } - return null; - } - - private boolean validateJavaVersion(String java) { - //TODO: fix for j16 -// final JavaVersion javaVersion = new DefaultJvmVersionDetector(new DefaultExecActionFactory(new IdentityFileResolver())).getJavaVersion(java); -// -// if (!javaVersion.getMajorVersion().equals("8")) { -// System.out.println("Failed to validate Java version " + javaVersion.toString() + " [" + java + "] for ProGuard libraryjars"); -// // throw new RuntimeException("Java version incorrect: " + javaVersion.getMajorVersion() + " for " + java); -// return false; -// } -// -// System.out.println("Validated Java version " + javaVersion.toString() + " [" + java + "] for ProGuard libraryjars"); - return true; + return toolchain; } private void generateConfigs() throws Exception { @@ -252,12 +182,12 @@ public class ProguardTask extends BaritoneGradleTask { private void proguardApi() throws Exception { runProguard(getTemporaryFile(compType + PROGUARD_API_CONFIG)); - Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString(), Arrays.asList(pathfinder), false); + Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString(), List.of(), false); } private void proguardStandalone() throws Exception { runProguard(getTemporaryFile(compType + PROGUARD_STANDALONE_CONFIG)); - Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString(), Arrays.asList(pathfinder), false); + Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString(), List.of(), false); } private static final class Pair { @@ -285,13 +215,8 @@ public class ProguardTask extends BaritoneGradleTask { } catch (IOException ignored) {} } - public void setUrl(String url) { - this.url = url; - } - - - public void setExtract(String extract) { - this.extract = extract; + public void setProguardVersion(String url) { + this.proguardVersion = url; } private void runProguard(Path config) throws Exception { @@ -300,39 +225,15 @@ public class ProguardTask extends BaritoneGradleTask { Files.delete(this.proguardOut); } - // Make paths relative to work directory; fixes spaces in path to config, @"" doesn't work Path workingDirectory = getTemporaryFile(""); - Path proguardJar = workingDirectory.relativize(getTemporaryFile(PROGUARD_JAR)); - config = workingDirectory.relativize(config); - // Honestly, if you still have spaces in your path at this point, you're SOL. + getProject().javaexec(spec -> { + spec.workingDir(workingDirectory.toFile()); + spec.args("@" + workingDirectory.relativize(config)); + spec.classpath(getTemporaryFile(String.format(PROGUARD_JAR, proguardVersion))); - Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString()) - .directory(workingDirectory.toFile()) // Set the working directory to the temporary folder] - .start(); - - // We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this - this.printOutputLog(p.getInputStream(), System.out); - this.printOutputLog(p.getErrorStream(), System.err); - - // Halt the current thread until the process is complete, if the exit code isn't 0, throw an exception - int exitCode = p.waitFor(); - if (exitCode != 0) { - Thread.sleep(1000); - throw new IllegalStateException("Proguard exited with code " + exitCode); - } + spec.executable(getJavaLauncherForProguard().getExecutablePath().getAsFile()); + }).assertNormalExitValue().rethrowFailure(); } - private void printOutputLog(InputStream stream, PrintStream outerr) { - new Thread(() -> { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { - String line; - while ((line = reader.readLine()) != null) { - outerr.println(line); - } - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - } } diff --git a/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java b/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java index 781aaec24..04bd74947 100644 --- a/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java +++ b/buildSrc/src/main/java/baritone/gradle/util/Determinizer.java @@ -71,10 +71,10 @@ public class Determinizer { ByteArrayOutputStream cancer = new ByteArrayOutputStream(); copy(jarFile.getInputStream(entry), cancer); String manifest = new String(cancer.toByteArray()); - if (!manifest.contains("baritone.launch.BaritoneTweaker")) { + if (!manifest.contains("baritone.launch.tweaker.BaritoneTweaker")) { throw new IllegalStateException("unable to replace"); } - manifest = manifest.replace("baritone.launch.BaritoneTweaker", "org.spongepowered.asm.launch.MixinTweaker"); + manifest = manifest.replace("baritone.launch.tweaker.BaritoneTweaker", "org.spongepowered.asm.launch.MixinTweaker"); jos.write(manifest.getBytes()); } else { copy(jarFile.getInputStream(entry), jos); diff --git a/fabric/build.gradle b/fabric/build.gradle index c88ff80ef..caeb009aa 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -19,15 +19,14 @@ import baritone.gradle.task.CreateDistTask import baritone.gradle.task.ProguardTask plugins { - id "com.github.johnrengelman.shadow" version "7.0.0" + id "com.github.johnrengelman.shadow" version "8.0.0" } archivesBaseName = archivesBaseName + "-fabric" -minecraft { - fabric() - runs.client = { - jvmArgs.add("-XstartOnFirstThread") +unimined.minecraft { + fabric { + loader project.fabric_version } } @@ -39,8 +38,6 @@ configurations { } dependencies { - fabric "net.fabricmc:fabric-loader:${project.fabric_version}" - // because of multiple sourcesets `common project(":")` doesn't work for (sourceSet in rootProject.sourceSets) { if (sourceSet == rootProject.sourceSets.test) continue @@ -48,6 +45,7 @@ dependencies { common sourceSet.output shadowCommon sourceSet.output } + include "dev.babbaj:nether-pathfinder:${project.nether_pathfinder_version}" } processResources { @@ -60,17 +58,17 @@ processResources { shadowJar { configurations = [project.configurations.shadowCommon] - classifier "dev-shadow" + archiveClassifier.set "dev-shadow" } remapJar { inputFile.set shadowJar.archiveFile dependsOn shadowJar - classifier null + archiveClassifier.set null } jar { - classifier "dev" + archiveClassifier.set "dev" } components.java { @@ -80,8 +78,7 @@ components.java { } task proguard(type: ProguardTask) { - url 'https://github.com/Guardsquare/proguard/releases/download/v7.2.1/proguard-7.2.1.zip' - extract 'proguard-7.2.1/lib/proguard.jar' + proguardVersion "7.2.1" compType "fabric" } @@ -103,4 +100,4 @@ publishing { repositories { // Add repositories to publish to here. } -} \ No newline at end of file +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 66f1ee1aa..801c293bd 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -11,7 +11,8 @@ ], "contact": { "homepage": "https://github.com/cabaletta/baritone", - "sources": "https://github.com/cabaletta/baritone" + "sources": "https://github.com/cabaletta/baritone", + "issues": "https://github.com/cabaletta/baritone/issues" }, "license": "LGPL-3.0", @@ -27,5 +28,12 @@ "depends": { "fabricloader": ">=0.11.0", "minecraft": ">=1.20 <=1.20.1" + }, + "custom": { + "modmenu": { + "links": { + "modmenu.discord": "https://discord.gg/s6fRBAUpmr" + } + } } } diff --git a/forge/build.gradle b/forge/build.gradle index bac8ca54a..b2c81567e 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -19,15 +19,19 @@ import baritone.gradle.task.CreateDistTask import baritone.gradle.task.ProguardTask plugins { - id "com.github.johnrengelman.shadow" version "7.0.0" + id "com.github.johnrengelman.shadow" version "8.0.0" } archivesBaseName = archivesBaseName + "-forge" -minecraft { +unimined.minecraft { + mappings { + devFallbackNamespace "intermediary" + } + forge { - devFallbackNamespace = "intermediary" - mixinConfig = ["mixins.baritone.json"] + loader project.forge_version + mixinConfig ["mixins.baritone.json"] } } @@ -45,8 +49,6 @@ configurations { } dependencies { - forge "net.minecraftforge:forge:${rootProject.forge_version}" - // because of multiple sourcesets `common project(":")` doesn't work for (sourceSet in rootProject.sourceSets) { if (sourceSet == rootProject.sourceSets.test) continue @@ -54,6 +56,7 @@ dependencies { common sourceSet.output shadowCommon sourceSet.output } + shadowCommon "dev.babbaj:nether-pathfinder:${project.nether_pathfinder_version}" } processResources { @@ -66,17 +69,17 @@ processResources { shadowJar { configurations = [project.configurations.shadowCommon] - classifier "dev-shadow" + archiveClassifier.set "dev-shadow" } remapJar { inputFile.set shadowJar.archiveFile dependsOn shadowJar - classifier null + archiveClassifier.set null } jar { - classifier "dev" + archiveClassifier.set "dev" manifest { attributes( @@ -96,8 +99,7 @@ components.java { } task proguard(type: ProguardTask) { - url 'https://github.com/Guardsquare/proguard/releases/download/v7.2.1/proguard-7.2.1.zip' - extract 'proguard-7.2.1/lib/proguard.jar' + proguardVersion "7.2.1" compType "forge" } diff --git a/gradle.properties b/gradle.properties index f665e9537..6793cc3a8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,17 @@ mod_version=1.10.1 maven_group=baritone archives_base_name=baritone +java_version=17 + minecraft_version=1.20.1 -forge_version=1.20.1-47.0.1 + +forge_version=47.0.1 + fabric_version=0.14.18 + +nether_pathfinder_version=1.4.1 + +// These dependencies are used for common and tweaker +// while mod loaders usually ship their own version +mixin_version=0.8.5 +asm_version=9.3 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 00e33edef..15de90249 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/scripts/proguard.pro b/scripts/proguard.pro index 34b76170f..0b764e4d9 100644 --- a/scripts/proguard.pro +++ b/scripts/proguard.pro @@ -54,6 +54,11 @@ -dontwarn baritone.utils.schematic.schematica.** -dontwarn baritone.utils.schematic.litematica.** +# nether-pathfinder uses JNI to acess its own classes +# and some of our builds include it before running proguard +# conservatively keep all of it, even though only PathSegment. is needed +-keep,allowoptimization class dev.babbaj.pathfinder.** { *; } + # Keep - Applications. Keep all application classes, along with their 'main' # methods. -keepclasseswithmembers public class * { diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index adbbd6eaa..44dabae2a 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -29,6 +29,11 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.awt.*; import java.lang.annotation.ElementType; @@ -50,6 +55,7 @@ import java.util.function.Consumer; * @author leijurv */ public final class Settings { + private static final Logger LOGGER = LoggerFactory.getLogger("Baritone"); /** * Allow Baritone to break blocks @@ -71,6 +77,16 @@ public final class Settings { */ public final Setting allowPlace = new Setting<>(true); + /** + * Allow Baritone to place blocks in fluid source blocks + */ + public final Setting allowPlaceInFluidsSource = new Setting<>(true); + + /** + * Allow Baritone to place blocks in flowing fluid + */ + public final Setting allowPlaceInFluidsFlow = new Setting<>(true); + /** * Allow Baritone to move items in your inventory to your hotbar */ @@ -382,6 +398,12 @@ public final class Settings { */ public final Setting blockReachDistance = new Setting<>(4.5f); + /** + * How many ticks between breaking a block and starting to break the next block. Default in game is 6 ticks. + * Values under 1 will be clamped. The delay only applies to non-instant (1-tick) breaks. + */ + public final Setting blockBreakSpeed = new Setting<>(6); + /** * How many degrees to randomize the pitch and yaw every tick. Set to 0 to disable */ @@ -900,6 +922,13 @@ public final class Settings { */ public final Setting maxCachedWorldScanCount = new Setting<>(10); + /** + * Mine will not scan for or remember more than this many target locations. + * Note that the number of locations retrieved from cache is additionaly + * limited by {@link #maxCachedWorldScanCount}. + */ + public final Setting mineMaxOreLocationsCount = new Setting<>(64); + /** * Sets the minimum y level whilst mining - set to 0 to turn off. * if world has negative y values, subtract the min world height to get the value to put here @@ -957,6 +986,11 @@ public final class Settings { */ public final Setting replantNetherWart = new Setting<>(false); + /** + * Farming will scan for at most this many blocks. + */ + public final Setting farmMaxScanSize = new Setting<>(256); + /** * When the cache scan gives less blocks than the maximum threshold (but still above zero), scan the main world too. *

@@ -1048,6 +1082,11 @@ public final class Settings { */ public final Setting breakCorrectBlockPenaltyMultiplier = new Setting<>(10d); + /** + * Multiply the cost of placing a block that's incorrect in the builder's schematic by this coefficient + */ + public final Setting placeIncorrectBlockPenaltyMultiplier = new Setting<>(2d); + /** * When this setting is true, build a schematic with the highest X coordinate being the origin, instead of the lowest */ @@ -1063,6 +1102,28 @@ public final class Settings { */ public final Setting schematicOrientationZ = new Setting<>(false); + /** + * Rotates the schematic before building it. + * Possible values are + *

+ */ + public final Setting buildSchematicRotation = new Setting<>(Rotation.NONE); + + /** + * Mirrors the schematic before building it. + * Possible values are + * + */ + public final Setting buildSchematicMirror = new Setting<>(Mirror.NONE); + /** * The fallback used by the build command when no extension is specified. This may be useful if schematics of a * particular format are used often, and the user does not wish to have to specify the extension with every usage. @@ -1174,6 +1235,11 @@ public final class Settings { */ public final Setting followRadius = new Setting<>(3); + /** + * The maximum distance to the entity you're following + */ + public final Setting followTargetMaxDistance = new Setting<>(0); + /** * Turn this on if your exploration filter is enormous, you don't want it to check if it's done, * and you are just fine with it just hanging on completion @@ -1209,8 +1275,12 @@ public final class Settings { */ @JavaOnly public final Setting> logger = new Setting<>((msg) -> { - final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null; - Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag); + try { + final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null; + Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag); + } catch (Throwable t) { + LOGGER.warn("Failed to log message to chat: " + msg.getString(), t); + } }); /** @@ -1468,6 +1538,11 @@ public final class Settings { */ public final Setting elytraTermsAccepted = new Setting<>(false); + /** + * Verbose chat logging in elytra mode + */ + public final Setting elytraChatSpam = new Setting<>(false); + /** * A map of lowercase setting field names to their respective setting */ diff --git a/src/api/java/baritone/api/command/datatypes/BlockById.java b/src/api/java/baritone/api/command/datatypes/BlockById.java index f92c968a2..64cf0a760 100644 --- a/src/api/java/baritone/api/command/datatypes/BlockById.java +++ b/src/api/java/baritone/api/command/datatypes/BlockById.java @@ -23,17 +23,11 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; -import java.util.regex.Pattern; import java.util.stream.Stream; public enum BlockById implements IDatatypeFor { INSTANCE; - /** - * Matches (domain:)?name? where domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ respectively. - */ - private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?[a-z0-9/_.-]*"); - @Override public Block get(IDatatypeContext ctx) throws CommandException { ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString()); @@ -48,10 +42,6 @@ public enum BlockById implements IDatatypeFor { public Stream tabComplete(IDatatypeContext ctx) throws CommandException { String arg = ctx.getConsumer().getString(); - if (!PATTERN.matcher(arg).matches()) { - return Stream.empty(); - } - return new TabCompleteHelper() .append( BuiltInRegistries.BLOCK.keySet() diff --git a/src/api/java/baritone/api/command/datatypes/ItemById.java b/src/api/java/baritone/api/command/datatypes/ItemById.java new file mode 100644 index 000000000..eb4f230b4 --- /dev/null +++ b/src/api/java/baritone/api/command/datatypes/ItemById.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.api.command.datatypes; + +import baritone.api.command.exception.CommandException; +import baritone.api.command.helpers.TabCompleteHelper; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; + +import java.util.stream.Stream; + +public enum ItemById implements IDatatypeFor { + INSTANCE; + + @Override + public Item get(IDatatypeContext ctx) throws CommandException { + ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString()); + Item item; + if ((item = BuiltInRegistries.ITEM.getOptional(id).orElse(null)) == null) { + throw new IllegalArgumentException("No item found by that id"); + } + return item; + } + + @Override + public Stream tabComplete(IDatatypeContext ctx) throws CommandException { + return new TabCompleteHelper() + .append( + BuiltInRegistries.BLOCK.keySet() + .stream() + .map(ResourceLocation::toString) + ) + .filterPrefixNamespaced(ctx.getConsumer().getString()) + .sortAlphabetically() + .stream(); + } +} diff --git a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java index 4f822352a..88f603205 100644 --- a/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java +++ b/src/api/java/baritone/api/command/helpers/TabCompleteHelper.java @@ -212,7 +212,12 @@ public class TabCompleteHelper { * @return This {@link TabCompleteHelper} */ public TabCompleteHelper filterPrefixNamespaced(String prefix) { - return filterPrefix(new ResourceLocation(prefix).toString()); + ResourceLocation loc = ResourceLocation.tryParse(prefix); + if (loc == null) { + stream = Stream.empty(); + return this; + } + return filterPrefix(loc.toString()); } /** diff --git a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java index 49b6f708d..1a1b6e50c 100644 --- a/src/api/java/baritone/api/pathing/goals/GoalRunAway.java +++ b/src/api/java/baritone/api/pathing/goals/GoalRunAway.java @@ -44,7 +44,7 @@ public class GoalRunAway implements Goal { public GoalRunAway(double distance, Integer maintainY, BlockPos... from) { if (from.length == 0) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Positions to run away from must not be empty"); } this.from = from; this.distanceSq = (int) (distance * distance); diff --git a/src/api/java/baritone/api/process/IBuilderProcess.java b/src/api/java/baritone/api/process/IBuilderProcess.java index 77250ce73..67a3ed491 100644 --- a/src/api/java/baritone/api/process/IBuilderProcess.java +++ b/src/api/java/baritone/api/process/IBuilderProcess.java @@ -24,6 +24,7 @@ import net.minecraft.core.Vec3i; import net.minecraft.world.level.block.state.BlockState; import java.io.File; import java.util.List; +import java.util.Optional; /** * @author Brady @@ -74,4 +75,17 @@ public interface IBuilderProcess extends IBaritoneProcess { * cause it to give up. This is updated every tick, but only while the builder process is active. */ List getApproxPlaceable(); + /** + * Returns the lower bound of the current mining layer if mineInLayers is true. + * If mineInLayers is false, this will return an empty optional. + * @return The lower bound of the current mining layer + */ + Optional getMinLayer(); + + /** + * Returns the upper bound of the current mining layer if mineInLayers is true. + * If mineInLayers is false, this will return an empty optional. + * @return The upper bound of the current mining layer + */ + Optional getMaxLayer(); } diff --git a/src/api/java/baritone/api/process/IFollowProcess.java b/src/api/java/baritone/api/process/IFollowProcess.java index 6f7f0a239..e3ed73006 100644 --- a/src/api/java/baritone/api/process/IFollowProcess.java +++ b/src/api/java/baritone/api/process/IFollowProcess.java @@ -17,9 +17,11 @@ package baritone.api.process; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; + import java.util.List; import java.util.function.Predicate; -import net.minecraft.world.entity.Entity; /** * @author Brady @@ -34,6 +36,13 @@ public interface IFollowProcess extends IBaritoneProcess { */ void follow(Predicate filter); + /** + * Try to pick up any items matching this predicate + * + * @param filter the predicate + */ + void pickup(Predicate filter); + /** * @return The entities that are currently being followed. null if not currently following, empty if nothing matches the predicate */ diff --git a/src/api/java/baritone/api/schematic/ISchematicSystem.java b/src/api/java/baritone/api/schematic/ISchematicSystem.java index c8f039070..385cc0514 100644 --- a/src/api/java/baritone/api/schematic/ISchematicSystem.java +++ b/src/api/java/baritone/api/schematic/ISchematicSystem.java @@ -21,6 +21,7 @@ import baritone.api.command.registry.Registry; import baritone.api.schematic.format.ISchematicFormat; import java.io.File; +import java.util.List; import java.util.Optional; /** @@ -41,4 +42,9 @@ public interface ISchematicSystem { * @return The corresponding format for the file, {@link Optional#empty()} if no candidates were found. */ Optional getByFile(File file); + + /** + * @return A list of file extensions used by supported formats + */ + List getFileExtensions(); } diff --git a/src/api/java/baritone/api/schematic/MirroredSchematic.java b/src/api/java/baritone/api/schematic/MirroredSchematic.java new file mode 100644 index 000000000..b9e10808c --- /dev/null +++ b/src/api/java/baritone/api/schematic/MirroredSchematic.java @@ -0,0 +1,114 @@ +/* + * 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.world.level.block.state.BlockState; +import net.minecraft.world.level.block.Mirror; + +import java.util.List; +import java.util.stream.Collectors; + +public class MirroredSchematic implements ISchematic { + + private final ISchematic schematic; + private final Mirror mirror; + + public MirroredSchematic(ISchematic schematic, Mirror mirror) { + this.schematic = schematic; + this.mirror = mirror; + } + + @Override + public boolean inSchematic(int x, int y, int z, BlockState currentState) { + return schematic.inSchematic( + mirrorX(x, widthX(), mirror), + y, + mirrorZ(z, lengthZ(), mirror), + mirror(currentState, mirror) + ); + } + + @Override + public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { + return mirror(schematic.desiredState( + mirrorX(x, widthX(), mirror), + y, + mirrorZ(z, lengthZ(), mirror), + mirror(current, mirror), + mirror(approxPlaceable, mirror) + ), mirror); + } + + @Override + public void reset() { + schematic.reset(); + } + + @Override + public int widthX() { + return schematic.widthX(); + } + + @Override + public int heightY() { + return schematic.heightY(); + } + + @Override + public int lengthZ() { + return schematic.lengthZ(); + } + + private static int mirrorX(int x, int sizeX, Mirror mirror) { + switch (mirror) { + case NONE: + case LEFT_RIGHT: + return x; + case FRONT_BACK: + return sizeX - x - 1; + } + throw new IllegalArgumentException("Unknown mirror"); + } + + private static int mirrorZ(int z, int sizeZ, Mirror mirror) { + switch (mirror) { + case NONE: + case FRONT_BACK: + return z; + case LEFT_RIGHT: + return sizeZ - z - 1; + } + throw new IllegalArgumentException("Unknown mirror"); + } + + private static BlockState mirror(BlockState state, Mirror mirror) { + if (state == null) { + return null; + } + return state.mirror(mirror); + } + + private static List mirror(List states, Mirror mirror) { + if (states == null) { + return null; + } + return states.stream() + .map(s -> mirror(s, mirror)) + .collect(Collectors.toList()); + } +} diff --git a/src/api/java/baritone/api/schematic/RotatedSchematic.java b/src/api/java/baritone/api/schematic/RotatedSchematic.java new file mode 100644 index 000000000..e3c9ed7aa --- /dev/null +++ b/src/api/java/baritone/api/schematic/RotatedSchematic.java @@ -0,0 +1,136 @@ +/* + * 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.world.level.block.state.BlockState; +import net.minecraft.world.level.block.Rotation; + +import java.util.List; +import java.util.stream.Collectors; + +public class RotatedSchematic implements ISchematic { + + private final ISchematic schematic; + private final Rotation rotation; + private final Rotation inverseRotation; + + public RotatedSchematic(ISchematic schematic, Rotation rotation) { + this.schematic = schematic; + this.rotation = rotation; + // I don't think a 14 line switch would improve readability + this.inverseRotation = rotation.getRotated(rotation).getRotated(rotation); + } + + @Override + public boolean inSchematic(int x, int y, int z, BlockState currentState) { + return schematic.inSchematic( + rotateX(x, z, widthX(), lengthZ(), inverseRotation), + y, + rotateZ(x, z, widthX(), lengthZ(), inverseRotation), + rotate(currentState, inverseRotation) + ); + } + + @Override + public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { + return rotate(schematic.desiredState( + rotateX(x, z, widthX(), lengthZ(), inverseRotation), + y, + rotateZ(x, z, widthX(), lengthZ(), inverseRotation), + rotate(current, inverseRotation), + rotate(approxPlaceable, inverseRotation) + ), rotation); + } + + @Override + public void reset() { + schematic.reset(); + } + + @Override + public int widthX() { + return flipsCoordinates(rotation) ? schematic.lengthZ() : schematic.widthX(); + } + + @Override + public int heightY() { + return schematic.heightY(); + } + + @Override + public int lengthZ() { + return flipsCoordinates(rotation) ? schematic.widthX() : schematic.lengthZ(); + } + + /** + * Wether {@code rotation} swaps the x and z components + */ + private static boolean flipsCoordinates(Rotation rotation) { + return rotation == Rotation.CLOCKWISE_90 || rotation == Rotation.COUNTERCLOCKWISE_90; + } + + /** + * The x component of x,y after applying the rotation + */ + private static int rotateX(int x, int z, int sizeX, int sizeZ, Rotation rotation) { + switch (rotation) { + case NONE: + return x; + case CLOCKWISE_90: + return sizeZ - z - 1; + case CLOCKWISE_180: + return sizeX - x - 1; + case COUNTERCLOCKWISE_90: + return z; + } + throw new IllegalArgumentException("Unknown rotation"); + } + + /** + * The z component of x,y after applying the rotation + */ + private static int rotateZ(int x, int z, int sizeX, int sizeZ, Rotation rotation) { + switch (rotation) { + case NONE: + return z; + case CLOCKWISE_90: + return x; + case CLOCKWISE_180: + return sizeZ - z - 1; + case COUNTERCLOCKWISE_90: + return sizeX - x - 1; + } + throw new IllegalArgumentException("Unknown rotation"); + } + + private static BlockState rotate(BlockState state, Rotation rotation) { + if (state == null) { + return null; + } + return state.rotate(rotation); + } + + private static List rotate(List states, Rotation rotation) { + if (states == null) { + return null; + } + return states.stream() + .map(s -> rotate(s, rotation)) + .collect(Collectors.toList()); + } +} diff --git a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java index 3fe045bcf..0ccf059b0 100644 --- a/src/api/java/baritone/api/schematic/format/ISchematicFormat.java +++ b/src/api/java/baritone/api/schematic/format/ISchematicFormat.java @@ -23,6 +23,7 @@ import baritone.api.schematic.IStaticSchematic; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.List; /** * The base of a {@link ISchematic} file format @@ -42,4 +43,9 @@ public interface ISchematicFormat { * @return Whether or not the specified file matches this schematic format */ boolean isFileType(File file); + + /** + * @return A list of file extensions used by this format + */ + List getFileExtensions(); } diff --git a/src/api/java/baritone/api/utils/IPlayerContext.java b/src/api/java/baritone/api/utils/IPlayerContext.java index a97475a5b..de6d7cd58 100644 --- a/src/api/java/baritone/api/utils/IPlayerContext.java +++ b/src/api/java/baritone/api/utils/IPlayerContext.java @@ -99,6 +99,14 @@ public interface IPlayerContext { return new Rotation(player().getYRot(), player().getXRot()); } + /** + * Returns the player's eye height, taking into account whether or not the player is sneaking. + * + * @param ifSneaking Whether or not the player is sneaking + * @return The player's eye height + * @deprecated Use entity.getEyeHeight(Pose.CROUCHING) instead + */ + @Deprecated static double eyeHeight(boolean ifSneaking) { return ifSneaking ? 1.27 : 1.62; } diff --git a/src/api/java/baritone/api/utils/RayTraceUtils.java b/src/api/java/baritone/api/utils/RayTraceUtils.java index 5541f562b..354f9c87d 100644 --- a/src/api/java/baritone/api/utils/RayTraceUtils.java +++ b/src/api/java/baritone/api/utils/RayTraceUtils.java @@ -18,6 +18,7 @@ package baritone.api.utils; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Pose; import net.minecraft.world.level.ClipContext; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; @@ -62,6 +63,6 @@ public final class RayTraceUtils { } public static Vec3 inferSneakingEyePosition(Entity entity) { - return new Vec3(entity.getX(), entity.getY() + IPlayerContext.eyeHeight(true), entity.getZ()); + return new Vec3(entity.getX(), entity.getY() + entity.getEyeHeight(Pose.CROUCHING), entity.getZ()); } } diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java index 53283cd33..7a18b61c3 100644 --- a/src/api/java/baritone/api/utils/SettingsUtil.java +++ b/src/api/java/baritone/api/utils/SettingsUtil.java @@ -27,6 +27,9 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; + import java.awt.*; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -149,7 +152,7 @@ public class SettingsUtil { throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting.getName()); } - return io.toString(new ParserContext(setting), value); + return io.toString(setting.getType(), value); } public static String settingValueToString(Settings.Setting setting) throws IllegalArgumentException { @@ -196,7 +199,7 @@ public class SettingsUtil { } Class intendedType = setting.getValueClass(); ISettingParser ioMethod = Parser.getParser(setting.getType()); - Object parsed = ioMethod.parse(new ParserContext(setting), settingValue); + Object parsed = ioMethod.parse(setting.getType(), settingValue); if (!intendedType.isInstance(parsed)) { throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass()); } @@ -205,26 +208,13 @@ public class SettingsUtil { private interface ISettingParser { - T parse(ParserContext context, String raw); + T parse(Type type, String raw); - String toString(ParserContext context, T value); + String toString(Type type, T value); boolean accepts(Type type); } - private static class ParserContext { - - private final Settings.Setting setting; - - private ParserContext(Settings.Setting setting) { - this.setting = setting; - } - - private Settings.Setting getSetting() { - return this.setting; - } - } - private enum Parser implements ISettingParser { DOUBLE(Double.class, Double::parseDouble), @@ -233,7 +223,8 @@ public class SettingsUtil { FLOAT(Float.class, Float::parseFloat), LONG(Long.class, Long::parseLong), STRING(String.class, String::new), - DIRECTION(Direction.class, Direction::byName), + MIRROR(Mirror.class, Mirror::valueOf, Mirror::name), + ROTATION(Rotation.class, Rotation::valueOf, Rotation::name), COLOR( Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), @@ -256,21 +247,21 @@ public class SettingsUtil { ), LIST() { @Override - public Object parse(ParserContext context, String raw) { - Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; - Parser parser = Parser.getParser(type); + public Object parse(Type type, String raw) { + Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; + Parser parser = Parser.getParser(elementType); return Stream.of(raw.split(",")) - .map(s -> parser.parse(context, s)) + .map(s -> parser.parse(elementType, s)) .collect(Collectors.toList()); } @Override - public String toString(ParserContext context, Object value) { - Type type = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0]; - Parser parser = Parser.getParser(type); + public String toString(Type type, Object value) { + Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; + Parser parser = Parser.getParser(elementType); return ((List) value).stream() - .map(o -> parser.toString(context, o)) + .map(o -> parser.toString(elementType, o)) .collect(Collectors.joining(",")); } @@ -281,26 +272,26 @@ public class SettingsUtil { }, 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]; + public Object parse(Type type, String raw) { + Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) type).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]))); + .collect(Collectors.toMap(s -> keyParser.parse(keyType, s[0]), s -> valueParser.parse(valueType, 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]; + public String toString(Type type, Object value) { + Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0]; + Type valueType = ((ParameterizedType) type).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())) + .map(o -> keyParser.toString(keyType, o.getKey()) + "->" + valueParser.toString(valueType, o.getValue())) .collect(Collectors.joining(",")); } @@ -331,14 +322,14 @@ public class SettingsUtil { } @Override - public Object parse(ParserContext context, String raw) { + public Object parse(Type type, String raw) { Object parsed = this.parser.apply(raw); Objects.requireNonNull(parsed); return parsed; } @Override - public String toString(ParserContext context, Object value) { + public String toString(Type type, Object value) { return this.toString.apply(value); } diff --git a/src/launch/java/baritone/launch/mixins/MixinPlayerController.java b/src/launch/java/baritone/launch/mixins/MixinPlayerController.java index 34f39aee9..7a77d4849 100644 --- a/src/launch/java/baritone/launch/mixins/MixinPlayerController.java +++ b/src/launch/java/baritone/launch/mixins/MixinPlayerController.java @@ -31,6 +31,10 @@ public abstract class MixinPlayerController implements IPlayerControllerMP { @Override public abstract void setIsHittingBlock(boolean isHittingBlock); + @Accessor("isDestroying") + @Override + public abstract boolean isHittingBlock(); + @Accessor("destroyBlockPos") @Override public abstract BlockPos getCurrentBlock(); @@ -38,4 +42,8 @@ public abstract class MixinPlayerController implements IPlayerControllerMP { @Invoker("ensureHasSentCarriedItem") @Override public abstract void callSyncCurrentPlayItem(); + + @Accessor("destroyDelay") + @Override + public abstract void setDestroyDelay(int destroyDelay); } diff --git a/src/launch/java/baritone/launch/mixins/MixinScreen.java b/src/launch/java/baritone/launch/mixins/MixinScreen.java index c99c7776c..84e72c7e0 100644 --- a/src/launch/java/baritone/launch/mixins/MixinScreen.java +++ b/src/launch/java/baritone/launch/mixins/MixinScreen.java @@ -21,17 +21,19 @@ import baritone.api.BaritoneAPI; import baritone.api.IBaritone; import baritone.api.event.events.ChatEvent; import baritone.utils.accessor.IGuiScreen; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Style; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; - -import java.net.URI; -import net.minecraft.client.gui.screens.Screen; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import java.net.URI; + +import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX; + @Mixin(Screen.class) public abstract class MixinScreen implements IGuiScreen { @@ -47,9 +49,13 @@ public abstract class MixinScreen implements IGuiScreen { if (clickEvent == null) { return; } + String command = clickEvent.getValue(); + if (command == null || !command.startsWith(FORCE_COMMAND_PREFIX)) { + return; + } IBaritone baritone = BaritoneAPI.getProvider().getPrimaryBaritone(); if (baritone != null) { - baritone.getGameEventHandler().onSendChatMessage(new ChatEvent(clickEvent.getValue())); + baritone.getGameEventHandler().onSendChatMessage(new ChatEvent(command)); } cir.setReturnValue(true); cir.cancel(); diff --git a/src/main/java/baritone/Baritone.java b/src/main/java/baritone/Baritone.java index c1176a3d4..ad6871413 100755 --- a/src/main/java/baritone/Baritone.java +++ b/src/main/java/baritone/Baritone.java @@ -79,7 +79,7 @@ public class Baritone implements IBaritone { private final ExploreProcess exploreProcess; private final FarmProcess farmProcess; private final InventoryPauserProcess inventoryPauserProcess; - private final ElytraProcess elytraProcess; + private final IElytraProcess elytraProcess; private final PathingControlManager pathingControlManager; private final SelectionManager selectionManager; diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index b7c035598..9e62765a2 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -265,7 +265,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, if (goal == null) { return false; } - if (goal.isInGoal(ctx.playerFeet()) || goal.isInGoal(expectedSegmentStart)) { + if (goal.isInGoal(ctx.playerFeet())) { return false; } synchronized (pathPlanLock) { @@ -553,7 +553,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, }); } - private static AbstractNodeCostSearch createPathfinder(BlockPos start, Goal goal, IPath previous, CalculationContext context) { + private AbstractNodeCostSearch createPathfinder(BlockPos start, Goal goal, IPath previous, CalculationContext context) { Goal transformed = goal; if (Baritone.settings().simplifyUnloadedYCoord.value && goal instanceof IGoalRenderPos) { BlockPos pos = ((IGoalRenderPos) goal).getGoalPos(); @@ -562,7 +562,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } } Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous, context); - return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoring, context); + BetterBlockPos feet = ctx.playerFeet(); + var realStart = new BetterBlockPos(start); + var sub = feet.subtract(realStart); + if (feet.getY() == realStart.getY() && Math.abs(sub.getX()) <= 1 && Math.abs(sub.getZ()) <= 1) { + realStart = feet; + } + return new AStarPathFinder(realStart, start.getX(), start.getY(), start.getZ(), transformed, favoring, context); + } @Override diff --git a/src/main/java/baritone/cache/CachedWorld.java b/src/main/java/baritone/cache/CachedWorld.java index e456382e6..aed1faeb5 100644 --- a/src/main/java/baritone/cache/CachedWorld.java +++ b/src/main/java/baritone/cache/CachedWorld.java @@ -196,9 +196,7 @@ public final class CachedWorld implements ICachedWorld, Helper { int distZ = ((region.getZ() << 9) + 256) - pruneCenter.getZ(); double dist = Math.sqrt(distX * distX + distZ * distZ); if (dist > 1024) { - if (!Baritone.settings().censorCoordinates.value) { - logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram"); - } + logDebug("Deleting cached region from ram"); cachedRegions.remove(getRegionID(region.getX(), region.getZ())); } } diff --git a/src/main/java/baritone/cache/FasterWorldScanner.java b/src/main/java/baritone/cache/FasterWorldScanner.java index 694b482ab..e364fd7b4 100644 --- a/src/main/java/baritone/cache/FasterWorldScanner.java +++ b/src/main/java/baritone/cache/FasterWorldScanner.java @@ -20,6 +20,7 @@ package baritone.cache; import baritone.api.cache.ICachedWorld; import baritone.api.cache.IWorldScanner; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.BlockOptionalMeta; import baritone.api.utils.BlockOptionalMetaLookup; import baritone.api.utils.IPlayerContext; import baritone.utils.accessor.IPalettedContainer; @@ -31,7 +32,13 @@ import net.minecraft.util.BitStorage; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.*; +import net.minecraft.world.level.chunk.GlobalPalette; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.Palette; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.SingleValuePalette; import java.util.ArrayList; import java.util.List; @@ -41,6 +48,8 @@ import java.util.stream.Stream; public enum FasterWorldScanner implements IWorldScanner { INSTANCE; + private static final BlockState[] PALETTE_REGISTRY_SENTINEL = new BlockState[0]; + @Override public List scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) { assert ctx.world() != null; @@ -147,7 +156,7 @@ public enum FasterWorldScanner implements IWorldScanner { long chunkX = (long) pos.x << 4; long chunkZ = (long) pos.z << 4; - int playerSectionY = ctx.playerFeet().y >> 4; + int playerSectionY = (ctx.playerFeet().y - ctx.world().getMinBuildHeight()) >> 4; return collectChunkSections(lookup, chunkProvider.getChunk(pos.x, pos.z, false), chunkX, chunkZ, playerSectionY).stream(); } @@ -183,7 +192,28 @@ public enum FasterWorldScanner implements IWorldScanner { return; } - boolean[] isInFilter = getIncludedFilterIndices(lookup, ((IPalettedContainer) sectionContainer).getPalette()); + Palette palette = ((IPalettedContainer) sectionContainer).getPalette(); + + if (palette instanceof SingleValuePalette) { + // single value palette doesn't have any data + if (lookup.has(palette.valueFor(0))) { + // TODO this is 4k hits, maybe don't return all of them? + for (int x = 0; x < 16; ++x) { + for (int y = 0; y < 16; ++y) { + for (int z = 0; z < 16; ++z) { + blocks.add(new BlockPos( + (int) chunkX + x, + sectionY + y, + (int) chunkZ + z + )); + } + } + } + } + return; + } + + boolean[] isInFilter = getIncludedFilterIndices(lookup, palette); if (isInFilter.length == 0) { return; } @@ -212,13 +242,18 @@ public enum FasterWorldScanner implements IWorldScanner { private boolean[] getIncludedFilterIndices(BlockOptionalMetaLookup lookup, Palette palette) { boolean commonBlockFound = false; - IdMapper paletteMap = getPalette(palette); - int size = paletteMap.size(); + BlockState[] paletteMap = getPalette(palette); + + if (paletteMap == PALETTE_REGISTRY_SENTINEL) { + return getIncludedFilterIndicesFromRegistry(lookup); + } + + int size = paletteMap.length; boolean[] isInFilter = new boolean[size]; for (int i = 0; i < size; i++) { - BlockState state = paletteMap.byId(i); + BlockState state = paletteMap[i]; if (lookup.has(state)) { isInFilter[i] = true; commonBlockFound = true; @@ -233,21 +268,34 @@ public enum FasterWorldScanner implements IWorldScanner { return isInFilter; } + private boolean[] getIncludedFilterIndicesFromRegistry(BlockOptionalMetaLookup lookup) { + boolean[] isInFilter = new boolean[Block.BLOCK_STATE_REGISTRY.size()]; + + for (BlockOptionalMeta bom : lookup.blocks()) { + for (BlockState state : bom.getAllBlockStates()) { + isInFilter[Block.BLOCK_STATE_REGISTRY.getId(state)] = true; + } + } + + return isInFilter; + } + /** * cheats to get the actual map of id -> blockstate from the various palette implementations */ - private static IdMapper getPalette(Palette palette) { + private static BlockState[] getPalette(Palette palette) { if (palette instanceof GlobalPalette) { - return Block.BLOCK_STATE_REGISTRY; + // copying the entire registry is not nice so we treat it as a special case + return PALETTE_REGISTRY_SENTINEL; } else { FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); palette.write(buf); int size = buf.readVarInt(); - IdMapper states = new IdMapper<>(); + BlockState[] states = new BlockState[size]; for (int i = 0; i < size; i++) { BlockState state = Block.BLOCK_STATE_REGISTRY.byId(buf.readVarInt()); assert state != null; - states.addMapping(state, i); + states[i] = state; } return states; } diff --git a/src/main/java/baritone/command/defaults/BuildCommand.java b/src/main/java/baritone/command/defaults/BuildCommand.java index bb34254ae..f9ddd33ef 100644 --- a/src/main/java/baritone/command/defaults/BuildCommand.java +++ b/src/main/java/baritone/command/defaults/BuildCommand.java @@ -26,11 +26,13 @@ import baritone.api.command.datatypes.RelativeFile; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidStateException; import baritone.api.utils.BetterBlockPos; +import baritone.utils.schematic.SchematicSystem; import org.apache.commons.io.FilenameUtils; import java.io.File; import java.util.Arrays; import java.util.List; +import java.util.StringJoiner; import java.util.stream.Stream; public class BuildCommand extends Command { @@ -44,10 +46,29 @@ public class BuildCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { - File file = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile(); + final File file0 = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile(); + File file = file0; if (FilenameUtils.getExtension(file.getAbsolutePath()).isEmpty()) { file = new File(file.getAbsolutePath() + "." + Baritone.settings().schematicFallbackExtension.value); } + if (!file.exists()) { + if (file0.exists()) { + throw new CommandInvalidStateException(String.format( + "Cannot load %s because I do not know which schematic format" + + " that is. Please rename the file to include the correct" + + " file extension.", + file)); + } + throw new CommandInvalidStateException("Cannot find " + file); + } + if (!SchematicSystem.INSTANCE.getByFile(file).isPresent()) { + StringJoiner formats = new StringJoiner(", "); + SchematicSystem.INSTANCE.getFileExtensions().forEach(formats::add); + throw new CommandInvalidStateException(String.format( + "Unsupported schematic format. Reckognized file extensions are: %s", + formats + )); + } BetterBlockPos origin = ctx.playerFeet(); BetterBlockPos buildOrigin; if (args.hasAny()) { @@ -59,7 +80,7 @@ public class BuildCommand extends Command { } boolean success = baritone.getBuilderProcess().build(file.getName(), file, buildOrigin); if (!success) { - throw new CommandInvalidStateException("Couldn't load the schematic. Make sure to use the FULL file name, including the extension (e.g. blah.schematic)."); + throw new CommandInvalidStateException("Couldn't load the schematic. Either your schematic is corrupt or this is a bug."); } logDirect(String.format("Successfully loaded schematic for building\nOrigin: %s", buildOrigin)); } diff --git a/src/main/java/baritone/command/defaults/DefaultCommands.java b/src/main/java/baritone/command/defaults/DefaultCommands.java index c810d07c1..5228a7ae1 100644 --- a/src/main/java/baritone/command/defaults/DefaultCommands.java +++ b/src/main/java/baritone/command/defaults/DefaultCommands.java @@ -53,6 +53,7 @@ public final class DefaultCommands { new RenderCommand(baritone), new FarmCommand(baritone), new FollowCommand(baritone), + new PickupCommand(baritone), new ExploreFilterCommand(baritone), new ReloadAllCommand(baritone), new SaveAllCommand(baritone), diff --git a/src/main/java/baritone/command/defaults/ElytraCommand.java b/src/main/java/baritone/command/defaults/ElytraCommand.java index 3f7b6bfd6..2f5eff352 100644 --- a/src/main/java/baritone/command/defaults/ElytraCommand.java +++ b/src/main/java/baritone/command/defaults/ElytraCommand.java @@ -216,7 +216,7 @@ public class ElytraCommand extends Command { final String osArch = System.getProperty("os.arch"); final String osName = System.getProperty("os.name"); return String.format( - "Legacy architectures are not supported. Your CPU is %s and your operating system is %s. " + + "Failed loading native library. Your CPU is %s and your operating system is %s. " + "Supported architectures are 64 bit x86, and 64 bit ARM. Supported operating systems are Windows, " + "Linux, and Mac", osArch, osName diff --git a/src/main/java/baritone/command/defaults/LitematicaCommand.java b/src/main/java/baritone/command/defaults/LitematicaCommand.java index bfe0079b3..2e251b224 100644 --- a/src/main/java/baritone/command/defaults/LitematicaCommand.java +++ b/src/main/java/baritone/command/defaults/LitematicaCommand.java @@ -34,18 +34,9 @@ public class LitematicaCommand extends Command { @Override public void execute(String label, IArgConsumer args) throws CommandException { - int schematic = 0; - if (args.hasAny()) { - args.requireMax(1); - if (args.is(Integer.class)) { - schematic = args.getAs(Integer.class) - 1; - } - } - try { - baritone.getBuilderProcess().buildOpenLitematic(schematic); - } catch (IndexOutOfBoundsException e) { - logDirect("Pleas provide a valid index."); - } + args.requireMax(1); + int schematic = args.hasAny() ? args.getAs(Integer.class) - 1 : 0; + baritone.getBuilderProcess().buildOpenLitematic(schematic); } @Override diff --git a/src/main/java/baritone/command/defaults/PickupCommand.java b/src/main/java/baritone/command/defaults/PickupCommand.java new file mode 100644 index 000000000..7967dd023 --- /dev/null +++ b/src/main/java/baritone/command/defaults/PickupCommand.java @@ -0,0 +1,82 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.command.defaults; + +import baritone.api.IBaritone; +import baritone.api.command.Command; +import baritone.api.command.argument.IArgConsumer; +import baritone.api.command.datatypes.ItemById; +import baritone.api.command.exception.CommandException; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +public class PickupCommand extends Command { + + public PickupCommand(IBaritone baritone) { + super(baritone, "pickup"); + } + + @Override + public void execute(String label, IArgConsumer args) throws CommandException { + Set collecting = new HashSet<>(); + while (args.hasAny()) { + Item item = args.getDatatypeFor(ItemById.INSTANCE); + collecting.add(item); + } + if (collecting.isEmpty()) { + baritone.getFollowProcess().pickup(stack -> true); + logDirect("Picking up all items"); + } else { + baritone.getFollowProcess().pickup(stack -> collecting.contains(stack.getItem())); + logDirect("Picking up these items:"); + collecting.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).forEach(this::logDirect); + } + } + + @Override + public Stream tabComplete(String label, IArgConsumer args) throws CommandException { + while (args.has(2)) { + if (args.peekDatatypeOrNull(ItemById.INSTANCE) == null) { + return Stream.empty(); + } + args.get(); + } + return args.tabCompleteDatatype(ItemById.INSTANCE); + } + + @Override + public String getShortDesc() { + return "Pickup items"; + } + + @Override + public List getLongDesc() { + return Arrays.asList( + "Usage:", + "> pickup - Pickup anything", + "> pickup <...> - Pickup certain items" + ); + } +} diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java index 14d22b0b4..e789dcd97 100644 --- a/src/main/java/baritone/command/defaults/SelCommand.java +++ b/src/main/java/baritone/command/defaults/SelCommand.java @@ -227,12 +227,7 @@ public class SelCommand extends Command { } } } - ISchematic schematic = new StaticSchematic() {{ - states = blockstates; - x = size.getX(); - y = size.getY(); - z = size.getZ(); - }}; + ISchematic schematic = new StaticSchematic(blockstates); composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z); } clipboard = composite; diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index b37b598ff..1c58cbf20 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -22,6 +22,7 @@ import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.ActionCosts; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.SettingsUtil; import baritone.pathing.calc.openset.BinaryHeapOpenSet; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Moves; @@ -41,8 +42,8 @@ public final class AStarPathFinder extends AbstractNodeCostSearch { private final Favoring favoring; private final CalculationContext calcContext; - public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) { - super(startX, startY, startZ, goal, context); + public AStarPathFinder(BetterBlockPos realStart, int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) { + super(realStart, startX, startY, startZ, goal, context); this.favoring = favoring; this.calcContext = context; } @@ -96,7 +97,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch { numNodes++; if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) { logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, " + numMovementsConsidered + " movements considered"); - return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext)); + return Optional.of(new Path(realStart, startNode, currentNode, numNodes, goal, calcContext)); } for (Moves moves : allMoves) { int newX = currentNode.x + moves.xOffset; @@ -122,17 +123,39 @@ public final class AStarPathFinder extends AbstractNodeCostSearch { continue; } if (actionCost <= 0 || Double.isNaN(actionCost)) { - throw new IllegalStateException(moves + " calculated implausible cost " + actionCost); + throw new IllegalStateException(String.format( + "%s from %s %s %s calculated implausible cost %s", + moves, + SettingsUtil.maybeCensor(currentNode.x), + SettingsUtil.maybeCensor(currentNode.y), + SettingsUtil.maybeCensor(currentNode.z), + actionCost)); } - // check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation + // check destination after verifying it's not COST_INF -- some movements return COST_INF without adjusting the destination if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218 continue; } if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) { - throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ); + throw new IllegalStateException(String.format( + "%s from %s %s %s ended at x z %s %s instead of %s %s", + moves, + SettingsUtil.maybeCensor(currentNode.x), + SettingsUtil.maybeCensor(currentNode.y), + SettingsUtil.maybeCensor(currentNode.z), + SettingsUtil.maybeCensor(res.x), + SettingsUtil.maybeCensor(res.z), + SettingsUtil.maybeCensor(newX), + SettingsUtil.maybeCensor(newZ))); } if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) { - throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset)); + throw new IllegalStateException(String.format( + "%s from %s %s %s ended at y %s instead of %s", + moves, + SettingsUtil.maybeCensor(currentNode.x), + SettingsUtil.maybeCensor(currentNode.y), + SettingsUtil.maybeCensor(currentNode.z), + SettingsUtil.maybeCensor(res.y), + SettingsUtil.maybeCensor(currentNode.y + moves.yOffset))); } long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z); if (isFavoring) { diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index d20b519dc..0bfb6ac3f 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -36,6 +36,7 @@ import java.util.Optional; */ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { + protected final BetterBlockPos realStart; protected final int startX; protected final int startY; protected final int startZ; @@ -81,7 +82,8 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { */ protected static final double MIN_IMPROVEMENT = 0.01; - AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal, CalculationContext context) { + AbstractNodeCostSearch(BetterBlockPos realStart, int startX, int startY, int startZ, Goal goal, CalculationContext context) { + this.realStart = realStart; this.startX = startX; this.startY = startY; this.startZ = startZ; @@ -177,7 +179,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { @Override public Optional pathToMostRecentNodeConsidered() { - return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(startNode, node, 0, goal, context)); + return Optional.ofNullable(mostRecentConsidered).map(node -> new Path(realStart, startNode, node, 0, goal, context)); } @Override @@ -208,7 +210,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder, Helper { System.out.println("Path goes for " + Math.sqrt(dist) + " blocks"); logDebug("A* cost coefficient " + COEFFICIENTS[i]); } - return Optional.of(new Path(startNode, bestSoFar[i], numNodes, goal, context)); + return Optional.of(new Path(realStart, startNode, bestSoFar[i], numNodes, goal, context)); } } // instead of returning bestSoFar[0], be less misleading diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index f7bfbaa24..eba408058 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -27,6 +27,7 @@ import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; import baritone.pathing.path.CutoffPath; import baritone.utils.pathing.PathBase; +import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Collections; @@ -68,28 +69,40 @@ class Path extends PathBase { private volatile boolean verified; - Path(PathNode start, PathNode end, int numNodes, Goal goal, CalculationContext context) { - this.start = new BetterBlockPos(start.x, start.y, start.z); + Path(BetterBlockPos realStart, PathNode start, PathNode end, int numNodes, Goal goal, CalculationContext context) { this.end = new BetterBlockPos(end.x, end.y, end.z); this.numNodes = numNodes; this.movements = new ArrayList<>(); this.goal = goal; this.context = context; + PathNode current = end; - LinkedList tempPath = new LinkedList<>(); - LinkedList tempNodes = new LinkedList<>(); - // Repeatedly inserting to the beginning of an arraylist is O(n^2) - // Instead, do it into a linked list, then convert at the end + List tempPath = new ArrayList<>(); + List tempNodes = new ArrayList<>(); while (current != null) { - tempNodes.addFirst(current); - tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z)); + tempNodes.add(current); + tempPath.add(new BetterBlockPos(current.x, current.y, current.z)); current = current.previous; } - // Can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is - // inserting into a LinkedList keeps track of length, then when we addall (which calls .toArray) it's able - // to performantly do that conversion since it knows the length. - this.path = new ArrayList<>(tempPath); - this.nodes = new ArrayList<>(tempNodes); + + // If the position the player is at is different from the position we told A* to start from, + // and A* gave us no movements, then add a fake node that will allow a movement to be created + // that gets us to the single position in the path. + // See PathingBehavior#createPathfinder and https://github.com/cabaletta/baritone/pull/4519 + var startNodePos = new BetterBlockPos(start.x, start.y, start.z); + if (!realStart.equals(startNodePos) && start.equals(end)) { + this.start = realStart; + PathNode fakeNode = new PathNode(realStart.x, realStart.y, realStart.z, goal); + fakeNode.cost = 0; + tempNodes.add(fakeNode); + tempPath.add(realStart); + } else { + this.start = startNodePos; + } + + // Nodes are traversed last to first so we need to reverse the list + this.path = Lists.reverse(tempPath); + this.nodes = Lists.reverse(tempNodes); } @Override @@ -99,7 +112,7 @@ class Path extends PathBase { private boolean assembleMovements() { if (path.isEmpty() || !movements.isEmpty()) { - throw new IllegalStateException(); + throw new IllegalStateException("Path must not be empty"); } for (int i = 0; i < path.size() - 1; i++) { double cost = nodes.get(i + 1).cost - nodes.get(i).cost; @@ -132,7 +145,7 @@ class Path extends PathBase { @Override public IPath postProcess() { if (verified) { - throw new IllegalStateException(); + throw new IllegalStateException("Path must not be verified twice"); } verified = true; boolean failed = assembleMovements(); @@ -141,7 +154,7 @@ class Path extends PathBase { if (failed) { // at least one movement became impossible during calculation CutoffPath res = new CutoffPath(this, movements().size()); if (res.movements().size() != movements.size()) { - throw new IllegalStateException(); + throw new IllegalStateException("Path has wrong size after cutoff"); } return res; } @@ -153,7 +166,8 @@ class Path extends PathBase { @Override public List movements() { if (!verified) { - throw new IllegalStateException(); + // edge case note: this is called during verification + throw new IllegalStateException("Path not yet verified"); } return Collections.unmodifiableList(movements); } diff --git a/src/main/java/baritone/pathing/calc/PathNode.java b/src/main/java/baritone/pathing/calc/PathNode.java index 2b693338a..0911c6c04 100644 --- a/src/main/java/baritone/pathing/calc/PathNode.java +++ b/src/main/java/baritone/pathing/calc/PathNode.java @@ -20,6 +20,7 @@ package baritone.pathing.calc; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.ActionCosts; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.SettingsUtil; /** * A node in the path, containing the cost and steps to get to it. @@ -68,7 +69,12 @@ public final class PathNode { this.cost = ActionCosts.COST_INF; this.estimatedCostToGoal = goal.heuristic(x, y, z); if (Double.isNaN(estimatedCostToGoal)) { - throw new IllegalStateException(goal + " calculated implausible heuristic"); + throw new IllegalStateException(String.format( + "%s calculated implausible heuristic NaN at %s %s %s", + goal, + SettingsUtil.maybeCensor(x), + SettingsUtil.maybeCensor(y), + SettingsUtil.maybeCensor(z))); } this.heapPosition = -1; this.x = x; diff --git a/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java b/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java index 33f077b9d..1da8ed7e5 100644 --- a/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java +++ b/src/main/java/baritone/pathing/calc/openset/BinaryHeapOpenSet.java @@ -92,7 +92,7 @@ public final class BinaryHeapOpenSet implements IOpenSet { @Override public final PathNode removeLowest() { if (size == 0) { - throw new IllegalStateException(); + throw new IllegalStateException("Cannot remove from empty heap"); } PathNode result = array[1]; PathNode val = array[size]; diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java index 64aca2ceb..e84188a7f 100644 --- a/src/main/java/baritone/pathing/movement/CalculationContext.java +++ b/src/main/java/baritone/pathing/movement/CalculationContext.java @@ -161,6 +161,12 @@ public class CalculationContext { if (!worldBorder.canPlaceAt(x, z)) { return COST_INF; } + if (!Baritone.settings().allowPlaceInFluidsSource.value && current.getFluidState().isSource()) { + return COST_INF; + } + if (!Baritone.settings().allowPlaceInFluidsFlow.value && !current.getFluidState().isEmpty() && !current.getFluidState().isSource()) { + return COST_INF; + } return placeBlockCost; } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index f5c928cd4..211180c83 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -428,7 +428,7 @@ public interface MovementHelper extends ActionCosts, Helper { if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this return YES; } - if (block == Blocks.FARMLAND || block == Blocks.DIRT_PATH) { + if (block == Blocks.FARMLAND || block == Blocks.DIRT_PATH || block == Blocks.SOUL_SAND) { return YES; } if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) { diff --git a/src/main/java/baritone/pathing/movement/Moves.java b/src/main/java/baritone/pathing/movement/Moves.java index 87b5db6ac..312c8957c 100644 --- a/src/main/java/baritone/pathing/movement/Moves.java +++ b/src/main/java/baritone/pathing/movement/Moves.java @@ -347,7 +347,7 @@ public enum Moves { public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) { if (dynamicXZ || dynamicY) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Movements with dynamic offset must override `apply`"); } result.x = x + xOffset; result.y = y + yOffset; @@ -356,6 +356,6 @@ public enum Moves { } public double cost(CalculationContext context, int x, int y, int z) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("Movements must override `cost` or `apply`"); } } diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index d760f3a38..8a5359b5b 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -455,7 +455,9 @@ public class PathExecutor implements IPathExecutor, Helper { if (data != null) { BetterBlockPos fallDest = new BetterBlockPos(data.getB()); if (!path.positions().contains(fallDest)) { - throw new IllegalStateException(); + throw new IllegalStateException(String.format( + "Fall override at %s %s %s returned illegal destination %s %s %s", + current.getSrc(), fallDest)); } if (ctx.playerFeet().equals(fallDest)) { pathPosition = path.positions().indexOf(fallDest); @@ -603,7 +605,9 @@ public class PathExecutor implements IPathExecutor, Helper { } return SplicedPath.trySplice(path, next.path, false).map(path -> { if (!path.getDest().equals(next.getPath().getDest())) { - throw new IllegalStateException(); + throw new IllegalStateException(String.format( + "Path has end %s instead of %s after splicing", + path.getDest(), next.getPath().getDest())); } PathExecutor ret = new PathExecutor(behavior, path); ret.pathPosition = pathPosition; @@ -619,7 +623,9 @@ public class PathExecutor implements IPathExecutor, Helper { int cutoffAmt = Baritone.settings().pathHistoryCutoffAmount.value; CutoffPath newPath = new CutoffPath(path, cutoffAmt, path.length() - 1); if (!newPath.getDest().equals(path.getDest())) { - throw new IllegalStateException(); + throw new IllegalStateException(String.format( + "Path has end %s instead of %s after trimming its start", + newPath.getDest(), path.getDest())); } logDebug("Discarding earliest segment movements, length cut from " + path.length() + " to " + newPath.length()); PathExecutor ret = new PathExecutor(behavior, newPath); diff --git a/src/main/java/baritone/pathing/path/SplicedPath.java b/src/main/java/baritone/pathing/path/SplicedPath.java index 1ba497d81..7f083a662 100644 --- a/src/main/java/baritone/pathing/path/SplicedPath.java +++ b/src/main/java/baritone/pathing/path/SplicedPath.java @@ -92,7 +92,7 @@ public class SplicedPath extends PathBase { } int positionInSecond = second.positions().indexOf(first.positions().get(firstPositionInSecond)); if (!allowOverlapCutoff && positionInSecond != 0) { - throw new IllegalStateException(); + throw new IllegalStateException("Paths to be spliced are overlapping incorrectly"); } List positions = new ArrayList<>(); List movements = new ArrayList<>(); diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java index c484140fc..094d80f69 100644 --- a/src/main/java/baritone/process/BuilderProcess.java +++ b/src/main/java/baritone/process/BuilderProcess.java @@ -28,7 +28,10 @@ import baritone.api.process.PathingCommandType; import baritone.api.schematic.FillSchematic; import baritone.api.schematic.ISchematic; import baritone.api.schematic.IStaticSchematic; +import baritone.api.schematic.MaskSchematic; import baritone.api.schematic.SubstituteSchematic; +import baritone.api.schematic.RotatedSchematic; +import baritone.api.schematic.MirroredSchematic; import baritone.api.schematic.format.ISchematicFormat; import baritone.api.utils.*; import baritone.api.utils.input.Input; @@ -41,7 +44,6 @@ import baritone.utils.PathingCommandContext; import baritone.utils.schematic.MapArtSchematic; import baritone.utils.schematic.SelectionSchematic; import baritone.utils.schematic.SchematicSystem; -import baritone.utils.schematic.format.defaults.LitematicaSchematic; import baritone.utils.schematic.litematica.LitematicaHelper; import baritone.utils.schematic.schematica.SchematicaHelper; import com.google.common.collect.ImmutableMap; @@ -50,7 +52,6 @@ import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; -import net.minecraft.nbt.NbtIo; import net.minecraft.util.Tuple; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.BlockItem; @@ -75,7 +76,6 @@ import net.minecraft.world.phys.shapes.VoxelShape; import java.io.File; import java.io.FileInputStream; -import java.nio.file.Files; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -84,6 +84,14 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF; public final class BuilderProcess extends BaritoneProcessHelper implements IBuilderProcess { + private static final Set> ORIENTATION_PROPS = + ImmutableSet.of( + RotatedPillarBlock.AXIS, HorizontalDirectionalBlock.FACING, + StairBlock.FACING, StairBlock.HALF, StairBlock.SHAPE, + PipeBlock.NORTH, PipeBlock.EAST, PipeBlock.SOUTH, PipeBlock.WEST, PipeBlock.UP, + TrapDoorBlock.OPEN, TrapDoorBlock.HALF + ); + private HashSet incorrectPositions; private LongOpenHashSet observedCompleted; // positions that are completed even if they're out of render distance and we can't make sure right now private String name; @@ -110,6 +118,20 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!Baritone.settings().buildSubstitutes.value.isEmpty()) { this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value); } + if (Baritone.settings().buildSchematicMirror.value != net.minecraft.world.level.block.Mirror.NONE) { + this.schematic = new MirroredSchematic(this.schematic, Baritone.settings().buildSchematicMirror.value); + } + if (Baritone.settings().buildSchematicRotation.value != net.minecraft.world.level.block.Rotation.NONE) { + this.schematic = new RotatedSchematic(this.schematic, Baritone.settings().buildSchematicRotation.value); + } + // TODO this preserves the old behavior, but maybe we should bake the setting value right here + this.schematic = new MaskSchematic(this.schematic) { + @Override + public boolean partOfMask(int x, int y, int z, BlockState current) { + // partOfMask is only called inside the schematic so desiredState is not null + return !Baritone.settings().buildSkipBlocks.value.contains(this.desiredState(x, y, z, current, Collections.emptyList()).getBlock()); + } + }; int x = origin.getX(); int y = origin.getY(); int z = origin.getZ(); @@ -168,15 +190,15 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!format.isPresent()) { return false; } - ISchematic parsed; + IStaticSchematic parsed; try { parsed = format.get().parse(new FileInputStream(schematic)); } catch (Exception e) { e.printStackTrace(); return false; } - parsed = applyMapArtAndSelection(origin, (IStaticSchematic) parsed); - build(name, parsed, origin); + ISchematic schem = applyMapArtAndSelection(origin, parsed); + build(name, schem, origin); return true; } @@ -196,17 +218,10 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (SchematicaHelper.isSchematicaPresent()) { Optional> schematic = SchematicaHelper.getOpenSchematic(); if (schematic.isPresent()) { - IStaticSchematic s = schematic.get().getA(); + IStaticSchematic raw = 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(), - schem, - origin - ); + ISchematic schem = applyMapArtAndSelection(origin, raw); + this.build(raw.toString(), schem, origin); } else { logDirect("No schematic currently open"); } @@ -219,19 +234,13 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil public void buildOpenLitematic(int i) { if (LitematicaHelper.isLitematicaPresent()) { //if java.lang.NoSuchMethodError is thrown see comment in SchematicPlacementManager - if (LitematicaHelper.hasLoadedSchematic()) { - String name = LitematicaHelper.getName(i); - try { - LitematicaSchematic schematic1 = new LitematicaSchematic(NbtIo.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false); - Vec3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i); - ISchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i); - schematic2 = applyMapArtAndSelection(origin, (IStaticSchematic) schematic2); - build(name, schematic2, correctedOrigin); - } catch (Exception e) { - logDirect("Schematic File could not be loaded."); - } + if (LitematicaHelper.hasLoadedSchematic(i)) { + Tuple schematic = LitematicaHelper.getSchematic(i); + Vec3i correctedOrigin = schematic.getB(); + ISchematic schematic2 = applyMapArtAndSelection(correctedOrigin, schematic.getA()); + build(schematic.getA().toString(), schematic2, correctedOrigin); } else { - logDirect("No schematic currently loaded"); + logDirect(String.format("List of placements has no entry %s", i + 1)); } } else { logDirect("Litematica is not present"); @@ -362,7 +371,11 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (!placementPlausible(new BetterBlockPos(x, y, z), toPlace)) { continue; } - AABB aabb = placeAgainstState.getShape(ctx.world(), placeAgainstPos).bounds(); + VoxelShape shape = placeAgainstState.getShape(ctx.world(), placeAgainstPos); + if (shape.isEmpty()) { + continue; + } + AABB aabb = shape.bounds(); for (Vec3 placementMultiplier : aabbSideMultipliers(against)) { double placeX = placeAgainstPos.x + aabb.minX * placementMultiplier.x + aabb.maxX * (1 - placementMultiplier.x); double placeY = placeAgainstPos.y + aabb.minY * placementMultiplier.y + aabb.maxY * (1 - placementMultiplier.y); @@ -429,7 +442,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil double z = side.getStepZ() == 0 ? 0.5 : (1 + side.getStepZ()) / 2D; return new Vec3[]{new Vec3(x, 0.25, z), new Vec3(x, 0.75, z)}; default: // null - throw new IllegalStateException(); + throw new IllegalStateException("Unexpected side " + side); } } @@ -438,8 +451,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return onTick(calcFailed, isSafeToCancel, 0); } - public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) { - if (recursions > 1000) { // onTick calls itself, don't crash + private PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel, int recursions) { + if (recursions > 100) { // onTick calls itself, don't crash return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH); } approxPlaceable = approxPlaceable(36); @@ -683,8 +696,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil continue; } // this is not in render distance - if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ)) - && !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) { + if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))) { // and we've never seen this position be correct // therefore mark as incorrect incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); @@ -707,13 +719,16 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil List sourceLiquids = new ArrayList<>(); List flowingLiquids = new ArrayList<>(); Map missing = new HashMap<>(); + List outOfBounds = new ArrayList<>(); incorrectPositions.forEach(pos -> { BlockState state = bcc.bsi.get0(pos); if (state.getBlock() instanceof AirBlock) { - if (containsBlockState(approxPlaceable, bcc.getSchematic(pos.x, pos.y, pos.z, state))) { + BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state); + if (desired == null) { + outOfBounds.add(pos); + } else if (containsBlockState(approxPlaceable, desired)) { placeable.add(pos); } else { - BlockState desired = bcc.getSchematic(pos.x, pos.y, pos.z, state); missing.put(desired, 1 + missing.getOrDefault(desired, 0)); } } else { @@ -731,6 +746,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } } }); + incorrectPositions.removeAll(outOfBounds); List toBreak = new ArrayList<>(); breakable.forEach(pos -> toBreak.add(breakGoal(pos, bcc))); List toPlace = new ArrayList<>(); @@ -983,6 +999,22 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return paused ? "Builder Paused" : "Building " + name; } + @Override + public Optional getMinLayer() { + if (Baritone.settings().buildInLayers.value) { + return Optional.of(this.layer); + } + return Optional.empty(); + } + + @Override + public Optional getMaxLayer() { + if (Baritone.settings().buildInLayers.value) { + return Optional.of(this.stopAtHeight); + } + return Optional.empty(); + } + private List approxPlaceable(int size) { List result = new ArrayList<>(); for (int i = 0; i < size; i++) { @@ -1009,15 +1041,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return result; } - public static final Set> orientationProps = - ImmutableSet.of( - RotatedPillarBlock.AXIS, HorizontalDirectionalBlock.FACING, - StairBlock.FACING, StairBlock.HALF, StairBlock.SHAPE, - PipeBlock.NORTH, PipeBlock.EAST, PipeBlock.SOUTH, PipeBlock.WEST, PipeBlock.UP, - TrapDoorBlock.OPEN, TrapDoorBlock.HALF - ); - - private boolean sameBlockstate(BlockState first, BlockState second) { + private static boolean sameBlockstate(BlockState first, BlockState second) { if (first.getBlock() != second.getBlock()) { return false; } @@ -1030,7 +1054,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil ImmutableMap, Comparable> map2 = second.getValues(); for (Property prop : map1.keySet()) { if (map1.get(prop) != map2.get(prop) - && !(ignoreDirection && orientationProps.contains(prop)) + && !(ignoreDirection && ORIENTATION_PROPS.contains(prop)) && !ignoredProps.contains(prop.getName())) { return false; } @@ -1038,7 +1062,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return true; } - private boolean containsBlockState(Collection states, BlockState state) { + private static boolean containsBlockState(Collection states, BlockState state) { for (BlockState testee : states) { if (sameBlockstate(testee, state)) { return true; @@ -1047,7 +1071,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return false; } - private boolean valid(BlockState current, BlockState desired, boolean itemVerify) { + private static boolean valid(BlockState current, BlockState desired, boolean itemVerify) { if (desired == null) { return true; } @@ -1063,7 +1087,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil if (desired.getBlock() instanceof AirBlock && Baritone.settings().buildIgnoreBlocks.value.contains(current.getBlock())) { return true; } - if (Baritone.settings().buildSkipBlocks.value.contains(desired.getBlock()) && !itemVerify) { + if (!(current.getBlock() instanceof AirBlock) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) { return true; } if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) { @@ -1109,12 +1133,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } BlockState sch = getSchematic(x, y, z, current); - if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) { + if (sch != null) { // TODO this can return true even when allowPlace is off.... is that an issue? if (sch.getBlock() instanceof AirBlock) { // we want this to be air, but they're asking if they can place here // this won't be a schematic block, this will be a throwaway - return placeBlockCost * 2; // we're going to have to break it eventually + return placeBlockCost * Baritone.settings().placeIncorrectBlockPenaltyMultiplier.value; // we're going to have to break it eventually } if (placeable.contains(sch)) { return 0; // thats right we gonna make it FREE to place a block where it should go in a structure @@ -1127,7 +1151,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil } // we want it to be something that we don't have // even more of a pain to place something wrong - return placeBlockCost * 3; + return placeBlockCost * 1.5 * Baritone.settings().placeIncorrectBlockPenaltyMultiplier.value; } else { if (hasThrowaway) { return placeBlockCost; @@ -1143,7 +1167,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil return COST_INF; } BlockState sch = getSchematic(x, y, z, current); - if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) { + if (sch != null) { if (sch.getBlock() instanceof AirBlock) { // it should be air // regardless of current contents, we can break it diff --git a/src/main/java/baritone/process/CustomGoalProcess.java b/src/main/java/baritone/process/CustomGoalProcess.java index d0dca9cbf..e101df74f 100644 --- a/src/main/java/baritone/process/CustomGoalProcess.java +++ b/src/main/java/baritone/process/CustomGoalProcess.java @@ -114,7 +114,7 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC } return new PathingCommand(this.goal, PathingCommandType.SET_GOAL_AND_PATH); default: - throw new IllegalStateException(); + throw new IllegalStateException("Unexpected state " + this.state); } } diff --git a/src/main/java/baritone/process/ElytraProcess.java b/src/main/java/baritone/process/ElytraProcess.java index 8e34b9f9e..fcd6c4b34 100644 --- a/src/main/java/baritone/process/ElytraProcess.java +++ b/src/main/java/baritone/process/ElytraProcess.java @@ -69,15 +69,25 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro private ElytraBehavior behavior; private boolean predictingTerrain; + @Override + public void onLostControl() { + this.state = State.START_FLYING; // TODO: null state? + this.goingToLandingSpot = false; + this.landingSpot = null; + this.reachedGoal = false; + this.goal = null; + destroyBehaviorAsync(); + } + private ElytraProcess(Baritone baritone) { super(baritone); baritone.getGameEventHandler().registerEventListener(this); } - public static T create(final Baritone baritone) { - return (T) (NetherPathfinderContext.isSupported() + public static IElytraProcess create(final Baritone baritone) { + return NetherPathfinderContext.isSupported() ? new ElytraProcess(baritone) - : new NullElytraProcess(baritone)); + : new NullElytraProcess(baritone); } @Override @@ -276,16 +286,6 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro this.state = State.FLYING; } - @Override - public void onLostControl() { - this.goal = null; - this.goingToLandingSpot = false; - this.landingSpot = null; - this.reachedGoal = false; - this.state = State.START_FLYING; // TODO: null state? - destroyBehaviorAsync(); - } - private void destroyBehaviorAsync() { ElytraBehavior behavior = this.behavior; if (behavior != null) { diff --git a/src/main/java/baritone/process/ExploreProcess.java b/src/main/java/baritone/process/ExploreProcess.java index 23fe7c23a..514a110e6 100644 --- a/src/main/java/baritone/process/ExploreProcess.java +++ b/src/main/java/baritone/process/ExploreProcess.java @@ -118,7 +118,9 @@ public final class ExploreProcess extends BaritoneProcessHelper implements IExpl int dz = (mult * 2 - 1) * zval; // dz can be either -zval or zval int trueDist = Math.abs(dx) + Math.abs(dz); if (trueDist != dist) { - throw new IllegalStateException(); + throw new IllegalStateException(String.format( + "Offset %s %s has distance %s, expected %s", + dx, dz, trueDist, dist)); } switch (filter.isAlreadyExplored(chunkX + dx, chunkZ + dz)) { case UNKNOWN: diff --git a/src/main/java/baritone/process/FarmProcess.java b/src/main/java/baritone/process/FarmProcess.java index c453beff2..4bb4fa947 100644 --- a/src/main/java/baritone/process/FarmProcess.java +++ b/src/main/java/baritone/process/FarmProcess.java @@ -42,6 +42,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.AirBlock; +import net.minecraft.world.level.block.BambooStalkBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.BonemealableBlock; @@ -95,6 +96,7 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro Items.NETHER_WART, Items.COCOA_BEANS, Blocks.SUGAR_CANE.asItem(), + Blocks.BAMBOO.asItem(), Blocks.CACTUS.asItem() ); @@ -137,6 +139,15 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro return true; } }, + BAMBOO(Blocks.BAMBOO, null) { + @Override + public boolean readyToHarvest(Level world, BlockPos pos, BlockState state) { + if (Baritone.settings().replantCrops.value) { + return world.getBlockState(pos.below()).getBlock() instanceof BambooStalkBlock; + } + return true; + } + }, CACTUS(Blocks.CACTUS, null) { @Override public boolean readyToHarvest(Level world, BlockPos pos, BlockState state) { @@ -191,20 +202,20 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { - ArrayList scan = new ArrayList<>(); - for (Harvest harvest : Harvest.values()) { - scan.add(harvest.block); - } - if (Baritone.settings().replantCrops.value) { - scan.add(Blocks.FARMLAND); - scan.add(Blocks.JUNGLE_LOG); - if (Baritone.settings().replantNetherWart.value) { - scan.add(Blocks.SOUL_SAND); - } - } - if (Baritone.settings().mineGoalUpdateInterval.value != 0 && tickCount++ % Baritone.settings().mineGoalUpdateInterval.value == 0) { - Baritone.getExecutor().execute(() -> locations = BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius(ctx, scan, 256, 10, 10)); + ArrayList scan = new ArrayList<>(); + for (Harvest harvest : Harvest.values()) { + scan.add(harvest.block); + } + if (Baritone.settings().replantCrops.value) { + scan.add(Blocks.FARMLAND); + scan.add(Blocks.JUNGLE_LOG); + if (Baritone.settings().replantNetherWart.value) { + scan.add(Blocks.SOUL_SAND); + } + } + + Baritone.getExecutor().execute(() -> locations = BaritoneAPI.getProvider().getWorldScanner().scanChunkRadius(ctx, scan, Baritone.settings().farmMaxScanSize.value, 10, 10)); } if (locations == null) { return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); @@ -256,7 +267,12 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } baritone.getInputOverrideHandler().clearAllKeys(); + BetterBlockPos playerPos = ctx.playerFeet(); + double blockReachDistance = ctx.playerController().getBlockReachDistance(); for (BlockPos pos : toBreak) { + if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) { + continue; + } Optional rot = RotationUtils.reachable(ctx, pos); if (rot.isPresent() && isSafeToCancel) { baritone.getLookBehavior().updateTarget(rot.get(), true); @@ -270,10 +286,13 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro ArrayList both = new ArrayList<>(openFarmland); both.addAll(openSoulsand); for (BlockPos pos : both) { + if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) { + continue; + } boolean soulsand = openSoulsand.contains(pos); - Optional rot = RotationUtils.reachableOffset(ctx, pos, new Vec3(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), ctx.playerController().getBlockReachDistance(), false); + Optional rot = RotationUtils.reachableOffset(ctx, pos, new Vec3(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5), blockReachDistance, false); if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, soulsand ? this::isNetherWart : this::isPlantable)) { - HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance()); + HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), blockReachDistance); if (result instanceof BlockHitResult && ((BlockHitResult) result).getDirection() == Direction.UP) { baritone.getLookBehavior().updateTarget(rot.get(), true); if (ctx.isLookingAt(pos)) { @@ -284,14 +303,17 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } } for (BlockPos pos : openLog) { + if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) { + continue; + } for (Direction dir : Direction.Plane.HORIZONTAL) { if (!(ctx.world().getBlockState(pos.relative(dir)).getBlock() instanceof AirBlock)) { continue; } Vec3 faceCenter = Vec3.atCenterOf(pos).add(Vec3.atLowerCornerOf(dir.getNormal()).scale(0.5)); - Optional rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, ctx.playerController().getBlockReachDistance(), false); + Optional rot = RotationUtils.reachableOffset(ctx, pos, faceCenter, blockReachDistance, false); if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isCocoa)) { - HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), ctx.playerController().getBlockReachDistance()); + HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), rot.get(), blockReachDistance); if (result instanceof BlockHitResult && ((BlockHitResult) result).getDirection() == dir) { baritone.getLookBehavior().updateTarget(rot.get(), true); if (ctx.isLookingAt(pos)) { @@ -303,6 +325,9 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } } for (BlockPos pos : bonemealable) { + if (playerPos.distSqr(pos) > blockReachDistance * blockReachDistance) { + continue; + } Optional rot = RotationUtils.reachable(ctx, pos); if (rot.isPresent() && isSafeToCancel && baritone.getInventoryBehavior().throwaway(true, this::isBoneMeal)) { baritone.getLookBehavior().updateTarget(rot.get(), true); @@ -359,6 +384,14 @@ public final class FarmProcess extends BaritoneProcessHelper implements IFarmPro } } } + if (goalz.isEmpty()) { + logDirect("Farm failed"); + if (Baritone.settings().notificationOnFarmFail.value) { + logNotification("Farm failed", true); + } + onLostControl(); + return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); + } return new PathingCommand(new GoalComposite(goalz.toArray(new Goal[0])), PathingCommandType.SET_GOAL_AND_PATH); } diff --git a/src/main/java/baritone/process/FollowProcess.java b/src/main/java/baritone/process/FollowProcess.java index b123216a6..0be7a4e80 100644 --- a/src/main/java/baritone/process/FollowProcess.java +++ b/src/main/java/baritone/process/FollowProcess.java @@ -19,6 +19,7 @@ package baritone.process; import baritone.Baritone; import baritone.api.pathing.goals.Goal; +import baritone.api.pathing.goals.GoalBlock; import baritone.api.pathing.goals.GoalComposite; import baritone.api.pathing.goals.GoalNear; import baritone.api.pathing.goals.GoalXZ; @@ -27,11 +28,14 @@ import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommandType; import baritone.api.utils.BetterBlockPos; import baritone.utils.BaritoneProcessHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.item.ItemStack; + import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; /** * Follow an entity @@ -42,6 +46,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo private Predicate filter; private List cache; + private boolean into; // walk straight into the target, regardless of settings public FollowProcess(Baritone baritone) { super(baritone); @@ -56,12 +61,15 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo private Goal towards(Entity following) { BlockPos pos; - if (Baritone.settings().followOffsetDistance.value == 0) { + if (Baritone.settings().followOffsetDistance.value == 0 || into) { pos = following.blockPosition(); } else { GoalXZ g = GoalXZ.fromDirection(following.position(), Baritone.settings().followOffsetDirection.value, Baritone.settings().followOffsetDistance.value); pos = new BetterBlockPos(g.getX(), following.position().y, g.getZ()); } + if (into) { + return new GoalBlock(pos); + } return new GoalNear(pos, Baritone.settings().followRadius.value); } @@ -76,6 +84,10 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo if (entity.equals(ctx.player())) { return false; } + int maxDist = Baritone.settings().followTargetMaxDistance.value; + if (maxDist != 0 && entity.distanceToSqr(ctx.player()) > maxDist * maxDist) { + return false; + } return ctx.entitiesStream().anyMatch(entity::equals); } @@ -110,6 +122,13 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo @Override public void follow(Predicate filter) { this.filter = filter; + this.into = false; + } + + @Override + public void pickup(Predicate filter) { + this.filter = e -> e instanceof ItemEntity && filter.test(((ItemEntity) e).getItem()); + this.into = true; } @Override diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index 852e6ba3d..9a7a18f49 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -53,8 +53,6 @@ import static baritone.api.pathing.movement.ActionCosts.COST_INF; */ public final class MineProcess extends BaritoneProcessHelper implements IMineProcess { - private static final int ORE_LOCATIONS_COUNT = 64; - private BlockOptionalMetaLookup filter; private List knownOreLocations; private List blacklist; // inaccessible @@ -79,7 +77,6 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro int curr = ctx.player().getInventory().items.stream() .filter(stack -> filter.has(stack)) .mapToInt(ItemStack::getCount).sum(); - System.out.println("Currently have " + curr + " valid items"); if (curr >= desiredQuantity) { logDirect("Have " + curr + " valid items"); cancel(); @@ -121,7 +118,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro .filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ()) .filter(pos -> pos.getY() >= ctx.playerFeet().getY()) .filter(pos -> !(BlockStateInterface.get(ctx, pos).getBlock() instanceof AirBlock)) // after breaking a block, it takes mineGoalUpdateInterval ticks for it to actually update this list =( - .min(Comparator.comparingDouble(ctx.playerFeet()::distSqr)); + .min(Comparator.comparingDouble(ctx.playerFeet().above()::distSqr)); baritone.getInputOverrideHandler().clearAllKeys(); if (shaft.isPresent() && ctx.player().onGround()) { BlockPos pos = shaft.get(); @@ -186,7 +183,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro List locs = knownOreLocations; if (!locs.isEmpty()) { CalculationContext context = new CalculationContext(baritone); - List locs2 = prune(context, new ArrayList<>(locs), filter, ORE_LOCATIONS_COUNT, blacklist, droppedItemsScan()); + List locs2 = prune(context, new ArrayList<>(locs), filter, Baritone.settings().mineMaxOreLocationsCount.value, blacklist, droppedItemsScan()); // can't reassign locs, gotta make a new var locs2, because we use it in a lambda right here, and variables you use in a lambda must be effectively final Goal goal = new GoalComposite(locs2.stream().map(loc -> coalesce(loc, locs2, context)).toArray(Goal[]::new)); knownOreLocations = locs2; @@ -235,7 +232,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return; } List dropped = droppedItemsScan(); - List locs = searchWorld(context, filter, ORE_LOCATIONS_COUNT, already, blacklist, dropped); + List locs = searchWorld(context, filter, Baritone.settings().mineMaxOreLocationsCount.value, already, blacklist, dropped); locs.addAll(dropped); if (locs.isEmpty() && !Baritone.settings().exploreForBlocks.value) { logDirect("No locations for " + filter + " known, cancelling"); @@ -425,7 +422,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } } } - knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist, dropped); + knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, Baritone.settings().mineMaxOreLocationsCount.value, blacklist, dropped); return true; } @@ -488,7 +485,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro public static boolean plausibleToBreak(CalculationContext ctx, BlockPos pos) { - if (MovementHelper.getMiningDurationTicks(ctx, pos.getX(), pos.getY(), pos.getZ(), ctx.bsi.get0(pos), true) >= COST_INF) { + BlockState state = ctx.bsi.get0(pos); + if (MovementHelper.getMiningDurationTicks(ctx, pos.getX(), pos.getY(), pos.getZ(), state, true) >= COST_INF) { + return false; + } + if (MovementHelper.avoidBreaking(ctx.bsi, pos.getX(), pos.getY(), pos.getZ(), state)) { return false; } diff --git a/src/main/java/baritone/process/elytra/ElytraBehavior.java b/src/main/java/baritone/process/elytra/ElytraBehavior.java index 1c9ca9a33..8cdfd0e39 100644 --- a/src/main/java/baritone/process/elytra/ElytraBehavior.java +++ b/src/main/java/baritone/process/elytra/ElytraBehavior.java @@ -176,9 +176,9 @@ public final class ElytraBehavior implements Helper { .thenRun(() -> { final double distance = this.path.get(0).distanceTo(this.path.get(this.path.size() - 1)); if (this.completePath) { - logDirect(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); + logVerbose(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); } else { - logDirect(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); + logVerbose(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); } }) .whenComplete((result, ex) -> { @@ -233,9 +233,9 @@ public final class ElytraBehavior implements Helper { final double distance = this.path.get(0).distanceTo(this.path.get(recompute)); if (this.completePath) { - logDirect(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); + logVerbose(String.format("Computed path (%.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); } else { - logDirect(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); + logVerbose(String.format("Computed segment (Next %.1f blocks in %.4f seconds)", distance, (System.nanoTime() - start) / 1e9d)); } }) .whenComplete((result, ex) -> { @@ -245,7 +245,7 @@ public final class ElytraBehavior implements Helper { if (cause instanceof PathCalculationException) { logDirect("Failed to compute next segment"); if (ctx.player().distanceToSqr(pathStart.getCenter()) < 16 * 16) { - logDirect("Player is near the segment start, therefore repeating this calculation is pointless. Marking as complete"); + logVerbose("Player is near the segment start, therefore repeating this calculation is pointless. Marking as complete"); completePath = true; } } else { @@ -323,7 +323,7 @@ public final class ElytraBehavior implements Helper { if (ElytraBehavior.this.process.state != ElytraProcess.State.LANDING && this.ticksNearUnchanged > 100) { this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)) .thenRun(() -> { - logDirect("Recalculating segment, no progress in last 100 ticks"); + logVerbose("Recalculating segment, no progress in last 100 ticks"); }); this.ticksNearUnchanged = 0; return; @@ -350,7 +350,7 @@ public final class ElytraBehavior implements Helper { final long start = System.nanoTime(); this.pathRecalcSegment(rejoinMainPathAt) .thenRun(() -> { - logDirect(String.format("Recalculated segment around path blockage near %s %s %s (next %.1f blocks in %.4f seconds)", + logVerbose(String.format("Recalculated segment around path blockage near %s %s %s (next %.1f blocks in %.4f seconds)", SettingsUtil.maybeCensor(blockage.x), SettingsUtil.maybeCensor(blockage.y), SettingsUtil.maybeCensor(blockage.z), @@ -362,7 +362,7 @@ public final class ElytraBehavior implements Helper { } } if (!canSeeAny && rangeStartIncl < rangeEndExcl - 2 && process.state != ElytraProcess.State.GET_TO_JUMP) { - this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)).thenRun(() -> logDirect("Recalculated segment since no path points were visible")); + this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)).thenRun(() -> logVerbose("Recalculated segment since no path points were visible")); } } @@ -583,10 +583,10 @@ public final class ElytraBehavior implements Helper { trySwapElytra(); if (ctx.player().horizontalCollision) { - logDirect("hbonk"); + logVerbose("hbonk"); } if (ctx.player().verticalCollision) { - logDirect("vbonk"); + logVerbose("vbonk"); } final SolverContext solverContext = this.new SolverContext(false); @@ -611,14 +611,14 @@ public final class ElytraBehavior implements Helper { } if (solution == null) { - logDirect("no solution"); + logVerbose("no solution"); return; } baritone.getLookBehavior().updateTarget(solution.rotation, false); if (!solution.solvedPitch) { - logDirect("no pitch solution, probably gonna crash in a few ticks LOL!!!"); + logVerbose("no pitch solution, probably gonna crash in a few ticks LOL!!!"); return; } else { this.aimPos = new BetterBlockPos(solution.goingTo.x, solution.goingTo.y, solution.goingTo.z); @@ -760,7 +760,7 @@ public final class ElytraBehavior implements Helper { logDirect("no fireworks"); return; } - logDirect("attempting to use firework" + (forceUseFirework ? " (forced)" : "")); + logVerbose("attempting to use firework" + (forceUseFirework ? " (forced)" : "")); ctx.playerController().processRightClick(ctx.player(), ctx.world(), InteractionHand.MAIN_HAND); this.minimumBoostTicks = 10 * (1 + getFireworkBoost(ctx.player().getItemInHand(InteractionHand.MAIN_HAND)).orElse(0)); this.remainingFireworkTicks = 10; @@ -1319,4 +1319,10 @@ public final class ElytraBehavior implements Helper { queueWindowClick(ctx.player().inventoryMenu.containerId, slotId, 0, ClickType.PICKUP); } } + + void logVerbose(String message) { + if (Baritone.settings().elytraChatSpam.value) { + logDebug(message); + } + } } diff --git a/src/main/java/baritone/utils/BlockBreakHelper.java b/src/main/java/baritone/utils/BlockBreakHelper.java index 2d209c721..0c5cf6f00 100644 --- a/src/main/java/baritone/utils/BlockBreakHelper.java +++ b/src/main/java/baritone/utils/BlockBreakHelper.java @@ -17,7 +17,9 @@ package baritone.utils; +import baritone.api.BaritoneAPI; import baritone.api.utils.IPlayerContext; +import baritone.utils.accessor.IPlayerControllerMP; import net.minecraft.world.InteractionHand; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; @@ -27,9 +29,12 @@ import net.minecraft.world.phys.HitResult; * @since 8/25/2018 */ public final class BlockBreakHelper { + // base ticks between block breaks caused by tick logic + private static final int BASE_BREAK_DELAY = 1; private final IPlayerContext ctx; - private boolean didBreakLastTick; + private boolean wasHitting; + private int breakDelayTimer = 0; BlockBreakHelper(IPlayerContext ctx) { this.ctx = ctx; @@ -37,38 +42,46 @@ public final class BlockBreakHelper { public void stopBreakingBlock() { // The player controller will never be null, but the player can be - if (ctx.player() != null && didBreakLastTick) { - if (!ctx.playerController().hasBrokenBlock()) { - // insane bypass to check breaking succeeded - ctx.playerController().setHittingBlock(true); - } + if (ctx.player() != null && wasHitting) { + ctx.playerController().setHittingBlock(false); ctx.playerController().resetBlockRemoving(); - didBreakLastTick = false; + wasHitting = false; } } public void tick(boolean isLeftClick) { + if (breakDelayTimer > 0) { + breakDelayTimer--; + return; + } HitResult trace = ctx.objectMouseOver(); boolean isBlockTrace = trace != null && trace.getType() == HitResult.Type.BLOCK; if (isLeftClick && isBlockTrace) { - if (!didBreakLastTick) { + ctx.playerController().setHittingBlock(wasHitting); + if (ctx.playerController().hasBrokenBlock()) { ctx.playerController().syncHeldItem(); ctx.playerController().clickBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection()); ctx.player().swing(InteractionHand.MAIN_HAND); + } else { + if (ctx.playerController().onPlayerDamageBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection())) { + ctx.player().swing(InteractionHand.MAIN_HAND); + } + if (ctx.playerController().hasBrokenBlock()) { // block broken this tick + // break delay timer only applies for multi-tick block breaks like vanilla + breakDelayTimer = BaritoneAPI.getSettings().blockBreakSpeed.value - BASE_BREAK_DELAY; + // must reset controller's destroy delay to prevent the client from delaying itself unnecessarily + ((IPlayerControllerMP) ctx.minecraft().gameMode).setDestroyDelay(0); + } } - - // Attempt to break the block - if (ctx.playerController().onPlayerDamageBlock(((BlockHitResult) trace).getBlockPos(), ((BlockHitResult) trace).getDirection())) { - ctx.player().swing(InteractionHand.MAIN_HAND); - } - + // if true, we're breaking a block. if false, we broke the block this tick + wasHitting = !ctx.playerController().hasBrokenBlock(); + // this value will be reset by the MC client handling mouse keys + // since we're not spoofing the click keybind to the client, the client will stop the break if isDestroyingBlock is true + // we store and restore this value on the next tick to determine if we're breaking a block ctx.playerController().setHittingBlock(false); - - didBreakLastTick = true; - } else if (didBreakLastTick) { - stopBreakingBlock(); - didBreakLastTick = false; + } else { + wasHitting = false; } } } diff --git a/src/main/java/baritone/utils/BlockPlaceHelper.java b/src/main/java/baritone/utils/BlockPlaceHelper.java index 93b0c4408..ca8d50523 100644 --- a/src/main/java/baritone/utils/BlockPlaceHelper.java +++ b/src/main/java/baritone/utils/BlockPlaceHelper.java @@ -25,6 +25,8 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; public class BlockPlaceHelper { + // base ticks between places caused by tick logic + private static final int BASE_PLACE_DELAY = 1; private final IPlayerContext ctx; private int rightClickTimer; @@ -42,7 +44,7 @@ public class BlockPlaceHelper { if (!rightClickRequested || ctx.player().isHandsBusy() || mouseOver == null || mouseOver.getType() != HitResult.Type.BLOCK) { return; } - rightClickTimer = Baritone.settings().rightClickSpeed.value; + rightClickTimer = Baritone.settings().rightClickSpeed.value - BASE_PLACE_DELAY; for (InteractionHand hand : InteractionHand.values()) { if (ctx.playerController().processRightClickBlock(ctx.player(), ctx.world(), hand, (BlockHitResult) mouseOver) == InteractionResult.SUCCESS) { ctx.player().swing(hand); diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java index 2931b9392..19a0da57a 100644 --- a/src/main/java/baritone/utils/BlockStateInterface.java +++ b/src/main/java/baritone/utils/BlockStateInterface.java @@ -70,7 +70,7 @@ public class BlockStateInterface { } this.useTheRealWorld = !Baritone.settings().pathThroughCachedOnly.value; if (!ctx.minecraft().isSameThread()) { - throw new IllegalStateException(); + throw new IllegalStateException("BlockStateInterface must be constructed on the main thread"); } this.isPassableBlockPos = new BlockPos.MutableBlockPos(); this.access = new BlockStateInterfaceAccessWrapper(this); @@ -132,7 +132,7 @@ public class BlockStateInterface { prevCached = region; cached = region; } - BlockState type = cached.getBlock(x & 511, y, z & 511); + BlockState type = cached.getBlock(x & 511, y + world.dimensionType().minY(), z & 511); if (type == null) { return AIR; } diff --git a/src/main/java/baritone/utils/GuiClick.java b/src/main/java/baritone/utils/GuiClick.java index 113450d1c..48781e389 100644 --- a/src/main/java/baritone/utils/GuiClick.java +++ b/src/main/java/baritone/utils/GuiClick.java @@ -74,13 +74,11 @@ public class GuiClick extends Screen implements Helper { Vec3 far = toWorld(mx, my, 1); // "Use 0.945 that's what stack overflow says" - leijurv if (near != null && far != null) { - /// Vec3 viewerPos = new Vec3(PathRenderer.posX(), PathRenderer.posY(), PathRenderer.posZ()); LocalPlayer player = BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().player(); HitResult result = player.level().clip(new ClipContext(near.add(viewerPos), far.add(viewerPos), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); if (result != null && result.getType() == HitResult.Type.BLOCK) { currentMouseOver = ((BlockHitResult) result).getBlockPos(); - System.out.println("currentMouseOver = " + currentMouseOver); } } } diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index 3566cd23a..2205d62e7 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -68,7 +68,7 @@ public class PathingControlManager implements IPathingControlManager { for (IBaritoneProcess proc : processes) { proc.onLostControl(); if (proc.isActive() && !proc.isTemporary()) { // it's okay only for a temporary thing (like combat pause) to maintain control even if you say to cancel - throw new IllegalStateException(proc.displayName()); + throw new IllegalStateException(proc.displayName() + " stayed active after being cancelled"); } } } @@ -121,7 +121,7 @@ public class PathingControlManager implements IPathingControlManager { } break; default: - throw new IllegalStateException(); + throw new IllegalStateException("Unexpected command type " + command.commandType); } } diff --git a/src/main/java/baritone/utils/ToolSet.java b/src/main/java/baritone/utils/ToolSet.java index 38b1fafdd..ed4b166cf 100644 --- a/src/main/java/baritone/utils/ToolSet.java +++ b/src/main/java/baritone/utils/ToolSet.java @@ -177,7 +177,13 @@ public class ToolSet { * @return how long it would take in ticks */ public static double calculateSpeedVsBlock(ItemStack item, BlockState state) { - float hardness = state.getDestroySpeed(null, null); + float hardness; + try { + hardness = state.getDestroySpeed(null, null); + } catch (NullPointerException npe) { + // can't easily determine the hardness so treat it as unbreakable + return -1; + } if (hardness < 0) { return -1; } diff --git a/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java b/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java index 72e6f7ee3..55fa43316 100644 --- a/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java +++ b/src/main/java/baritone/utils/accessor/IPlayerControllerMP.java @@ -23,7 +23,11 @@ public interface IPlayerControllerMP { void setIsHittingBlock(boolean isHittingBlock); + boolean isHittingBlock(); + BlockPos getCurrentBlock(); void callSyncCurrentPlayItem(); + + void setDestroyDelay(int destroyDelay); } diff --git a/src/main/java/baritone/utils/player/BaritonePlayerController.java b/src/main/java/baritone/utils/player/BaritonePlayerController.java index 42ba49052..b7e729b70 100644 --- a/src/main/java/baritone/utils/player/BaritonePlayerController.java +++ b/src/main/java/baritone/utils/player/BaritonePlayerController.java @@ -20,7 +20,6 @@ package baritone.utils.player; import baritone.api.utils.IPlayerController; import baritone.utils.accessor.IPlayerControllerMP; import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -54,7 +53,7 @@ public final class BaritonePlayerController implements IPlayerController { @Override public boolean hasBrokenBlock() { - return ((IPlayerControllerMP) mc.gameMode).getCurrentBlock().getY() == -1; + return !((IPlayerControllerMP) mc.gameMode).isHittingBlock(); } @Override diff --git a/src/main/java/baritone/utils/schematic/MapArtSchematic.java b/src/main/java/baritone/utils/schematic/MapArtSchematic.java index 4f71aea64..723be3983 100644 --- a/src/main/java/baritone/utils/schematic/MapArtSchematic.java +++ b/src/main/java/baritone/utils/schematic/MapArtSchematic.java @@ -41,6 +41,7 @@ public class MapArtSchematic extends MaskSchematic { private static int[][] generateHeightMap(IStaticSchematic schematic) { int[][] heightMap = new int[schematic.widthX()][schematic.lengthZ()]; + int missingColumns = 0; for (int x = 0; x < schematic.widthX(); x++) { for (int z = 0; z < schematic.lengthZ(); z++) { BlockState[] column = schematic.getColumn(x, z); @@ -48,12 +49,14 @@ public class MapArtSchematic extends MaskSchematic { if (lowestBlockY.isPresent()) { heightMap[x][z] = lowestBlockY.getAsInt(); } else { - System.out.println("Column " + x + "," + z + " has no blocks, but it's apparently map art? wtf"); - System.out.println("Letting it be whatever"); - heightMap[x][z] = 256; + missingColumns++; + heightMap[x][z] = Integer.MAX_VALUE; } } } + if (missingColumns != 0) { + System.out.println(missingColumns + " columns had no block despite being in a map art, letting them be whatever"); + } return heightMap; } diff --git a/src/main/java/baritone/utils/schematic/SchematicSystem.java b/src/main/java/baritone/utils/schematic/SchematicSystem.java index 8afafa8c3..ec6e7f626 100644 --- a/src/main/java/baritone/utils/schematic/SchematicSystem.java +++ b/src/main/java/baritone/utils/schematic/SchematicSystem.java @@ -24,6 +24,7 @@ import baritone.utils.schematic.format.DefaultSchematicFormats; import java.io.File; import java.util.Arrays; +import java.util.List; import java.util.Optional; /** @@ -48,4 +49,9 @@ public enum SchematicSystem implements ISchematicSystem { public Optional getByFile(File file) { return this.registry.stream().filter(format -> format.isFileType(file)).findFirst(); } + + @Override + public List getFileExtensions() { + return this.registry.stream().map(ISchematicFormat::getFileExtensions).flatMap(List::stream).toList(); + } } diff --git a/src/main/java/baritone/utils/schematic/StaticSchematic.java b/src/main/java/baritone/utils/schematic/StaticSchematic.java index 5a110281b..0c875c724 100644 --- a/src/main/java/baritone/utils/schematic/StaticSchematic.java +++ b/src/main/java/baritone/utils/schematic/StaticSchematic.java @@ -32,6 +32,16 @@ public class StaticSchematic extends AbstractSchematic implements IStaticSchemat protected BlockState[][][] states; + public StaticSchematic() {} + + public StaticSchematic(BlockState[][][] states) { + this.states = states; + boolean empty = states.length == 0 || states[0].length == 0 || states[0][0].length == 0; + this.x = empty ? 0 : states.length; + this.z = empty ? 0 : states[0].length; + this.y = empty ? 0 : states[0][0].length; + } + @Override public BlockState desiredState(int x, int y, int z, BlockState current, List approxPlaceable) { return this.states[x][z][y]; diff --git a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java index 17fafc821..25ef7b0d9 100644 --- a/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java +++ b/src/main/java/baritone/utils/schematic/format/DefaultSchematicFormats.java @@ -22,13 +22,15 @@ import baritone.api.schematic.format.ISchematicFormat; import baritone.utils.schematic.format.defaults.LitematicaSchematic; import baritone.utils.schematic.format.defaults.MCEditSchematic; import baritone.utils.schematic.format.defaults.SpongeSchematic; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; import org.apache.commons.io.FilenameUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; +import java.util.Collections; +import java.util.List; /** * Default implementations of {@link ISchematicFormat} @@ -81,7 +83,7 @@ public enum DefaultSchematicFormats implements ISchematicFormat { case 5: //1.13-1.17 throw new UnsupportedOperationException("This litematic Version is too old."); case 6: //1.18+ - return new LitematicaSchematic(nbt, false); + return new LitematicaSchematic(nbt); default: throw new UnsupportedOperationException("Unsuported Version of a Litematica Schematic"); } @@ -98,4 +100,9 @@ public enum DefaultSchematicFormats implements ISchematicFormat { public boolean isFileType(File file) { return this.extension.equalsIgnoreCase(FilenameUtils.getExtension(file.getAbsolutePath())); } + + @Override + public List getFileExtensions() { + return Collections.singletonList(this.extension); + } } diff --git a/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java b/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java index 65cdec058..89684981e 100644 --- a/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java +++ b/src/main/java/baritone/utils/schematic/format/defaults/LitematicaSchematic.java @@ -17,8 +17,9 @@ package baritone.utils.schematic.format.defaults; +import baritone.api.schematic.CompositeSchematic; +import baritone.api.schematic.IStaticSchematic; import baritone.utils.schematic.StaticSchematic; -import net.minecraft.core.Registry; import net.minecraft.core.Vec3i; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; @@ -30,6 +31,7 @@ import net.minecraft.world.level.block.state.properties.Property; import org.apache.commons.lang3.Validate; import javax.annotation.Nullable; +import java.util.Collections; import java.util.Optional; /** @@ -39,35 +41,24 @@ import java.util.Optional; * @author rycbar * @since 22.09.2022 */ -public final class LitematicaSchematic extends StaticSchematic { - private final Vec3i offsetMinCorner; - private final CompoundTag nbt; +public final class LitematicaSchematic extends CompositeSchematic implements IStaticSchematic { /** * @param nbtTagCompound a decompressed file stream aka nbt data. * @param rotated if the schematic is rotated by 90°. */ - public LitematicaSchematic(CompoundTag nbtTagCompound, boolean rotated) { - this.nbt = nbtTagCompound; - this.offsetMinCorner = new Vec3i(getMinOfSchematic("x"), getMinOfSchematic("y"), getMinOfSchematic("z")); - this.y = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("y")); - - if (rotated) { - this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z")); - this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x")); - } else { - this.x = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("x")); - this.z = Math.abs(nbt.getCompound("Metadata").getCompound("EnclosingSize").getInt("z")); - } - this.states = new BlockState[this.x][this.z][this.y]; - fillInSchematic(); + public LitematicaSchematic(CompoundTag nbt) { + super(0, 0, 0); + fillInSchematic(nbt); } /** - * @return Array of subregion names. + * @return Array of subregion tags. */ - private static String[] getRegions(CompoundTag nbt) { - return nbt.getCompound("Regions").getAllKeys().toArray(new String[0]); + private static CompoundTag[] getRegions(CompoundTag nbt) { + return nbt.getCompound("Regions").getAllKeys().stream() + .map(nbt.getCompound("Regions")::getCompound) + .toArray(CompoundTag[]::new); } /** @@ -76,14 +67,10 @@ public final class LitematicaSchematic extends StaticSchematic { * @param s axis that should be read. * @return the lower coord of the requested axis. */ - private static int getMinOfSubregion(CompoundTag nbt, String subReg, String s) { - int a = nbt.getCompound("Regions").getCompound(subReg).getCompound("Position").getInt(s); - int b = nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt(s); - if (b < 0) { - b++; - } - return Math.min(a, a + b); - + private static int getMinOfSubregion(CompoundTag subReg, String s) { + int a = subReg.getCompound("Position").getInt(s); + int b = subReg.getCompound("Size").getInt(s); + return Math.min(a, a + b + 1); } /** @@ -110,7 +97,7 @@ public final class LitematicaSchematic extends StaticSchematic { private static BlockState getBlockState(Block block, CompoundTag properties) { BlockState blockState = block.defaultBlockState(); - for (Object key : properties.getAllKeys().toArray()) { + for (Object key : properties.getAllKeys()) { Property property = block.getStateDefinition().getProperty((String) key); String propertyValue = properties.getString((String) key); if (property != null) { @@ -146,43 +133,19 @@ public final class LitematicaSchematic extends StaticSchematic { * * @return the volume of the subregion. */ - private static long getVolume(CompoundTag nbt, String subReg) { - return Math.abs( - nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x") * - nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y") * - nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z")); - } - - /** - * @return array of Long values. - */ - private static long[] getBlockStates(CompoundTag nbt, String subReg) { - return nbt.getCompound("Regions").getCompound(subReg).getLongArray("BlockStates"); - } - - /** - * Subregion don't have to be the same size as the enclosing size of the schematic. If they are smaller we check here if the current block is part of the subregion. - * - * @param x coord of the block relative to the minimum corner. - * @param y coord of the block relative to the minimum corner. - * @param z coord of the block relative to the minimum corner. - * @return if the current block is part of the subregion. - */ - private static boolean inSubregion(CompoundTag nbt, String subReg, int x, int y, int z) { - return x >= 0 && y >= 0 && z >= 0 && - x < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("x")) && - y < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("y")) && - z < Math.abs(nbt.getCompound("Regions").getCompound(subReg).getCompound("Size").getInt("z")); + private static long getVolume(CompoundTag subReg) { + CompoundTag size = subReg.getCompound("Size"); + return Math.abs(size.getInt("x") * size.getInt("y") * size.getInt("z")); } /** * @param s axis. * @return the lowest coordinate of that axis of the schematic. */ - private int getMinOfSchematic(String s) { + private static int getMinOfSchematic(CompoundTag nbt, String s) { int n = Integer.MAX_VALUE; - for (String subReg : getRegions(nbt)) { - n = Math.min(n, getMinOfSubregion(nbt, subReg, s)); + for (CompoundTag subReg : getRegions(nbt)) { + n = Math.min(n, getMinOfSubregion(subReg, s)); } return n; } @@ -190,18 +153,18 @@ public final class LitematicaSchematic extends StaticSchematic { /** * reads the file data. */ - private void fillInSchematic() { - for (String subReg : getRegions(nbt)) { - ListTag usedBlockTypes = nbt.getCompound("Regions").getCompound(subReg).getList("BlockStatePalette", 10); + private void fillInSchematic(CompoundTag nbt) { + Vec3i offsetMinCorner = new Vec3i(getMinOfSchematic(nbt, "x"), getMinOfSchematic(nbt, "y"), getMinOfSchematic(nbt, "z")); + for (CompoundTag subReg : getRegions(nbt)) { + ListTag usedBlockTypes = subReg.getList("BlockStatePalette", 10); BlockState[] blockList = getBlockList(usedBlockTypes); int bitsPerBlock = getBitsPerBlock(usedBlockTypes.size()); - long regionVolume = getVolume(nbt, subReg); - long[] blockStateArray = getBlockStates(nbt, subReg); + long regionVolume = getVolume(subReg); + long[] blockStateArray = subReg.getLongArray("BlockStates"); LitematicaBitArray bitArray = new LitematicaBitArray(bitsPerBlock, regionVolume, blockStateArray); - - writeSubregionIntoSchematic(nbt, subReg, blockList, bitArray); + writeSubregionIntoSchematic(subReg, offsetMinCorner, blockList, bitArray); } } @@ -211,65 +174,30 @@ public final class LitematicaSchematic extends StaticSchematic { * @param blockList list with the different block types used in the schematic. * @param bitArray bit array that holds the placement pattern. */ - private void writeSubregionIntoSchematic(CompoundTag nbt, String subReg, BlockState[] blockList, LitematicaBitArray bitArray) { - Vec3i offsetSubregion = new Vec3i(getMinOfSubregion(nbt, subReg, "x"), getMinOfSubregion(nbt, subReg, "y"), getMinOfSubregion(nbt, subReg, "z")); + private void writeSubregionIntoSchematic(CompoundTag subReg, Vec3i offsetMinCorner, BlockState[] blockList, LitematicaBitArray bitArray) { + int offsetX = getMinOfSubregion(subReg, "x") - offsetMinCorner.getX(); + int offsetY = getMinOfSubregion(subReg, "y") - offsetMinCorner.getY(); + int offsetZ = getMinOfSubregion(subReg, "z") - offsetMinCorner.getZ(); + CompoundTag size = subReg.getCompound("Size"); + int sizeX = Math.abs(size.getInt("x")); + int sizeY = Math.abs(size.getInt("y")); + int sizeZ = Math.abs(size.getInt("z")); + BlockState[][][] states = new BlockState[sizeX][sizeZ][sizeY]; int index = 0; - for (int y = 0; y < this.y; y++) { - for (int z = 0; z < this.z; z++) { - for (int x = 0; x < this.x; x++) { - if (inSubregion(nbt, subReg, x, y, z)) { - this.states[x - (offsetMinCorner.getX() - offsetSubregion.getX())][z - (offsetMinCorner.getZ() - offsetSubregion.getZ())][y - (offsetMinCorner.getY() - offsetSubregion.getY())] = blockList[bitArray.getAt(index)]; - index++; - } + for (int y = 0; y < sizeY; y++) { + for (int z = 0; z < sizeZ; z++) { + for (int x = 0; x < sizeX; x++) { + states[x][z][y] = blockList[bitArray.getAt(index)]; + index++; } } } + this.put(new StaticSchematic(states), offsetX, offsetY, offsetZ); } - /** - * @return offset from the schematic origin to the minimum Corner as a Vec3i. - */ - public Vec3i getOffsetMinCorner() { - return offsetMinCorner; - } - - /** - * @return x size of the schematic. - */ - public int getX() { - return this.x; - } - - /** - * @return y size of the schematic. - */ - public int getY() { - return this.y; - } - - /** - * @return z size of the schematic. - */ - public int getZ() { - return this.z; - } - - /** - * @param x position relative to the minimum corner of the schematic. - * @param y position relative to the minimum corner of the schematic. - * @param z position relative to the minimum corner of the schematic. - * @param blockState new blockstate of the block at this position. - */ - public void setDirect(int x, int y, int z, BlockState blockState) { - this.states[x][z][y] = blockState; - } - - /** - * @param rotated if the schematic is rotated by 90°. - * @return a copy of the schematic. - */ - public LitematicaSchematic getCopy(boolean rotated) { - return new LitematicaSchematic(nbt, rotated); + @Override + public BlockState getDirect(int x, int y, int z) { + return desiredState(x, y, z, null, Collections.emptyList()); } /** diff --git a/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java b/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java index 3b05c23ef..febe985d2 100644 --- a/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java +++ b/src/main/java/baritone/utils/schematic/litematica/LitematicaHelper.java @@ -17,15 +17,26 @@ package baritone.utils.schematic.litematica; -import baritone.utils.schematic.format.defaults.LitematicaSchematic; +import baritone.api.schematic.CompositeSchematic; +import baritone.api.schematic.IStaticSchematic; +import baritone.utils.schematic.StaticSchematic; import fi.dy.masa.litematica.Litematica; import fi.dy.masa.litematica.data.DataManager; +import fi.dy.masa.litematica.schematic.placement.SchematicPlacement; +import fi.dy.masa.litematica.schematic.placement.SubRegionPlacement; +import fi.dy.masa.litematica.world.SchematicWorldHandler; +import fi.dy.masa.litematica.world.WorldSchematic; +import net.minecraft.core.BlockPos; import net.minecraft.core.Vec3i; +import net.minecraft.util.Tuple; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.state.BlockState; -import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; /** * Helper class that provides access or processes data related to Litmatica schematics. @@ -48,168 +59,98 @@ public final class LitematicaHelper { } /** - * @return if there are loaded schematics. + * @return if {@code i} is a valid placement index */ - public static boolean hasLoadedSchematic() { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().size() > 0; + public static boolean hasLoadedSchematic(int i) { + return 0 <= i && i < DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().size(); } - /** - * @param i index of the Schematic in the schematic placement list. - * @return the name of the requested schematic. - */ - public static String getName(int i) { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getName(); + private static SchematicPlacement getPlacement(int i) { + return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i); } - /** - * @param i index of the Schematic in the schematic placement list. - * @return the world coordinates of the schematic origin. This can but does not have to be the minimum corner. - */ - public static Vec3i getOrigin(int i) { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getOrigin(); - } - - /** - * @param i index of the Schematic in the schematic placement list. - * @return Filepath of the schematic file. - */ - public static File getSchematicFile(int i) { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getSchematicFile(); - } - - /** - * @param i index of the Schematic in the schematic placement list. - * @return rotation of the schematic placement. - */ - public static Rotation getRotation(int i) { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getRotation(); - } - - /** - * @param i index of the Schematic in the schematic placement list. - * @return the mirroring of the schematic placement. - */ - public static Mirror getMirror(int i) { - return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getMirror(); - } - - /** - * @param schematic original schematic. - * @param i index of the Schematic in the schematic placement list. - * @return the minimum corner coordinates of the schematic, after the original schematic got rotated and mirrored. - */ - public static Vec3i getCorrectedOrigin(LitematicaSchematic schematic, int i) { - int x = LitematicaHelper.getOrigin(i).getX(); - int y = LitematicaHelper.getOrigin(i).getY(); - int z = LitematicaHelper.getOrigin(i).getZ(); - int mx = schematic.getOffsetMinCorner().getX(); - int my = schematic.getOffsetMinCorner().getY(); - int mz = schematic.getOffsetMinCorner().getZ(); - int sx = (schematic.getX() - 1) * -1; - int sz = (schematic.getZ() - 1) * -1; - - Vec3i correctedOrigin; - Mirror mirror = LitematicaHelper.getMirror(i); - Rotation rotation = LitematicaHelper.getRotation(i); - - //todo there has to be a better way to do this but i cant finde it atm - switch (mirror) { - case FRONT_BACK: - case LEFT_RIGHT: - switch ((mirror.ordinal() * 2 + rotation.ordinal()) % 4) { - case 1: - correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + (sx - mx)); - break; - case 2: - correctedOrigin = new Vec3i(x + mx, y + my, z + (sz - mz)); - break; - case 3: - correctedOrigin = new Vec3i(x + mz, y + my, z + mx); - break; - default: - correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + mz); - break; - } - break; - default: - switch (rotation) { - case CLOCKWISE_90: - correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + mx); - break; - case CLOCKWISE_180: - correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + (sz - mz)); - break; - case COUNTERCLOCKWISE_90: - correctedOrigin = new Vec3i(x + mz, y + my, z + (sx - mx)); - break; - default: - correctedOrigin = new Vec3i(x + mx, y + my, z + mz); - break; - } - } - return correctedOrigin; - } - - /** - * @param in the xyz offsets of the block relative to the schematic minimum corner. - * @param sizeX size of the schematic in the x-axis direction. - * @param sizeZ size of the schematic in the z-axis direction. - * @param mirror the mirroring of the schematic placement. - * @return the corresponding xyz coordinates after mirroring them according to the given mirroring. - */ - public static Vec3i doMirroring(Vec3i in, int sizeX, int sizeZ, Mirror mirror) { - int xOut = in.getX(); - int zOut = in.getZ(); + private static Vec3i transform(Vec3i in, Mirror mirror, Rotation rotation) { + int x = in.getX(); + int z = in.getZ(); if (mirror == Mirror.LEFT_RIGHT) { - zOut = sizeZ - in.getZ(); + z = -z; } else if (mirror == Mirror.FRONT_BACK) { - xOut = sizeX - in.getX(); + x = -x; + } + switch (rotation) { + case CLOCKWISE_90: + return new Vec3i(-z, in.getY(), x); + case CLOCKWISE_180: + return new Vec3i(-x, in.getY(), -z); + case COUNTERCLOCKWISE_90: + return new Vec3i(z, in.getY(), -x); + default: + return new Vec3i(x, in.getY(), z); } - return new Vec3i(xOut, in.getY(), zOut); } /** - * @param in the xyz offsets of the block relative to the schematic minimum corner. - * @param sizeX size of the schematic in the x-axis direction. - * @param sizeZ size of the schematic in the z-axis direction. - * @return the corresponding xyz coordinates after rotation them 90° clockwise. + * @param i index of the Schematic in the schematic placement list. + * @return The transformed schematic and the position of its minimum corner */ - public static Vec3i rotate(Vec3i in, int sizeX, int sizeZ) { - return new Vec3i(sizeX - (sizeX - sizeZ) - in.getZ(), in.getY(), in.getX()); - } - - /** - * IDFK this just grew and it somehow works. If you understand how, pls tell me. - * - * @param schemIn give in the original schematic. - * @param i index of the Schematic in the schematic placement list. - * @return get it out rotated and mirrored. - */ - public static LitematicaSchematic blackMagicFuckery(LitematicaSchematic schemIn, int i) { - LitematicaSchematic tempSchem = schemIn.getCopy(LitematicaHelper.getRotation(i).ordinal() % 2 == 1); - for (int yCounter = 0; yCounter < schemIn.getY(); yCounter++) { - for (int zCounter = 0; zCounter < schemIn.getZ(); zCounter++) { - for (int xCounter = 0; xCounter < schemIn.getX(); xCounter++) { - Vec3i xyzHolder = new Vec3i(xCounter, yCounter, zCounter); - xyzHolder = LitematicaHelper.doMirroring(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1, LitematicaHelper.getMirror(i)); - for (int turns = 0; turns < LitematicaHelper.getRotation(i).ordinal(); turns++) { - if ((turns % 2) == 0) { - xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1); - } else { - xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getZ() - 1, schemIn.getX() - 1); - } + public static Tuple getSchematic(int i) { + SchematicPlacement placement = getPlacement(i); + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int minZ = Integer.MAX_VALUE; + HashMap subRegions = new HashMap<>(); + Level schematicWorld = SchematicWorldHandler.getSchematicWorld(); + for (Map.Entry entry : placement.getEnabledRelativeSubRegionPlacements().entrySet()) { + SubRegionPlacement subPlacement = entry.getValue(); + Vec3i pos = transform(subPlacement.getPos(), placement.getMirror(), placement.getRotation()); + Vec3i size = placement.getSchematic().getAreaSize(entry.getKey()); + size = transform(size, placement.getMirror(), placement.getRotation()); + size = transform(size, subPlacement.getMirror(), subPlacement.getRotation()); + int mx = Math.min(size.getX() + 1, 0); + int my = Math.min(size.getY() + 1, 0); + int mz = Math.min(size.getZ() + 1, 0); + minX = Math.min(minX, pos.getX() + mx); + minY = Math.min(minY, pos.getY() + my); + minZ = Math.min(minZ, pos.getZ() + mz); + BlockPos origin = placement.getOrigin().offset(pos).offset(mx, my, mz); + BlockState[][][] states = new BlockState[Math.abs(size.getX())][Math.abs(size.getZ())][Math.abs(size.getY())]; + for (int x = 0; x < states.length; x++) { + for (int z = 0; z < states[x].length; z++) { + for (int y = 0; y < states[x][z].length; y++) { + states[x][z][y] = schematicWorld.getBlockState(origin.offset(x, y, z)); } - BlockState state = schemIn.getDirect(xCounter, yCounter, zCounter); - try { - state = state.mirror(LitematicaHelper.getMirror(i)).rotate(LitematicaHelper.getRotation(i)); - } catch (NullPointerException e) { - //nothing to worry about it's just a hole in the schematic. - } - tempSchem.setDirect(xyzHolder.getX(), xyzHolder.getY(), xyzHolder.getZ(), state); } } + StaticSchematic schematic = new StaticSchematic(states); + subRegions.put(pos.offset(mx, my, mz), schematic); } - return tempSchem; + LitematicaPlacementSchematic composite = new LitematicaPlacementSchematic(placement.getName()); + for (Map.Entry entry : subRegions.entrySet()) { + Vec3i pos = entry.getKey().offset(-minX, -minY, -minZ); + composite.put(entry.getValue(), pos.getX(), pos.getY(), pos.getZ()); + } + return new Tuple<>(composite, placement.getOrigin().offset(minX, minY, minZ)); } -} \ No newline at end of file + + private static class LitematicaPlacementSchematic extends CompositeSchematic implements IStaticSchematic { + private final String name; + + public LitematicaPlacementSchematic(String name) { + super(0, 0, 0); + this.name = name; + } + + @Override + public BlockState getDirect(int x, int y, int z) { + if (inSchematic(x, y, z, null)) { + return desiredState(x, y, z, null, Collections.emptyList()); + } + return null; + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java b/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java index 4941e7cf3..3f5c6c98f 100644 --- a/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java +++ b/src/schematica_api/java/fi/dy/masa/litematica/data/DataManager.java @@ -20,14 +20,8 @@ package fi.dy.masa.litematica.data; import fi.dy.masa.litematica.schematic.placement.SchematicPlacementManager; public class DataManager { - public static final DataManager INSTANCE = new DataManager(); - private final SchematicPlacementManager schematicPlacementManager = new SchematicPlacementManager(); - - private static DataManager getInstance() { - return INSTANCE; - } public static SchematicPlacementManager getSchematicPlacementManager() { - return getInstance().schematicPlacementManager; + throw new LinkageError(); } } \ No newline at end of file diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java new file mode 100644 index 000000000..fc8ef5c6e --- /dev/null +++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/LitematicaSchematic.java @@ -0,0 +1,27 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package fi.dy.masa.litematica.schematic; + +import net.minecraft.core.BlockPos; + +public class LitematicaSchematic { + + public BlockPos getAreaSize(String name) { + throw new LinkageError(); + } +} \ No newline at end of file diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java index a267553a9..77f8b629e 100644 --- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java +++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacement.java @@ -17,19 +17,35 @@ package fi.dy.masa.litematica.schematic.placement; +import com.google.common.collect.ImmutableMap; +import fi.dy.masa.litematica.schematic.LitematicaSchematic; +import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; -public class SchematicPlacement extends SchematicPlacementUnloaded { - private Rotation rotation; - private Mirror mirror; +public class SchematicPlacement { + + public String getName() { + throw new LinkageError(); + } + + public BlockPos getOrigin() { + throw new LinkageError(); + } public Rotation getRotation() { - return this.rotation; + throw new LinkageError(); } public Mirror getMirror() { - return this.mirror; + throw new LinkageError(); } + public ImmutableMap getEnabledRelativeSubRegionPlacements() { + throw new LinkageError(); + } + + public LitematicaSchematic getSchematic() { + throw new LinkageError(); + } } \ No newline at end of file diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java index ab60e27fa..e7f810a5e 100644 --- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java +++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementManager.java @@ -17,15 +17,13 @@ package fi.dy.masa.litematica.schematic.placement; -import java.util.ArrayList; import java.util.List; public class SchematicPlacementManager { - private final List schematicPlacements = new ArrayList<>(); //in case of a java.lang.NoSuchMethodError try change the name of this method to getAllSchematicPlacements() //there are inconsistencies in the litematica mod about the naming of this method public List getAllSchematicsPlacements() { - return schematicPlacements; + throw new LinkageError(); } } \ No newline at end of file diff --git a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java similarity index 65% rename from src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java rename to src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java index 9e705dc7b..ec28ee95d 100644 --- a/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SchematicPlacementUnloaded.java +++ b/src/schematica_api/java/fi/dy/masa/litematica/schematic/placement/SubRegionPlacement.java @@ -18,26 +18,20 @@ package fi.dy.masa.litematica.schematic.placement; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; -import javax.annotation.Nullable; -import java.io.File; +public class SubRegionPlacement { -public class SchematicPlacementUnloaded { - protected String name = "?"; - @Nullable - protected File schematicFile; - protected BlockPos origin = BlockPos.ZERO; - - public String getName() { - return this.name; + public BlockPos getPos() { + throw new LinkageError(); } - @Nullable - public File getSchematicFile() { - return this.schematicFile; + public Rotation getRotation() { + throw new LinkageError(); } - public BlockPos getOrigin() { - return this.origin; + public Mirror getMirror() { + throw new LinkageError(); } } \ No newline at end of file diff --git a/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java b/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java new file mode 100644 index 000000000..dfe6e9807 --- /dev/null +++ b/src/schematica_api/java/fi/dy/masa/litematica/world/SchematicWorldHandler.java @@ -0,0 +1,25 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package fi.dy.masa.litematica.world; + +public class SchematicWorldHandler { + + public static WorldSchematic getSchematicWorld() { + throw new LinkageError(); + } +} diff --git a/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java b/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java new file mode 100644 index 000000000..58f28b3a6 --- /dev/null +++ b/src/schematica_api/java/fi/dy/masa/litematica/world/WorldSchematic.java @@ -0,0 +1,27 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package fi.dy.masa.litematica.world; + +import net.minecraft.world.level.Level; + +public abstract class WorldSchematic extends Level { + private WorldSchematic() { + super(null, null, null, null, null, false, false, 0, 0); + throw new LinkageError(); + } +} diff --git a/tweaker/build.gradle b/tweaker/build.gradle index 887d07cf2..3e4758c87 100644 --- a/tweaker/build.gradle +++ b/tweaker/build.gradle @@ -20,13 +20,13 @@ import baritone.gradle.task.ProguardTask //import baritone.gradle.task.TweakerJsonAssembler plugins { - id "com.github.johnrengelman.shadow" version "7.0.0" + id "com.github.johnrengelman.shadow" version "8.0.0" } -minecraft { +unimined.minecraft { runs.client = { mainClass = "net.minecraft.launchwrapper.Launch" - args.addAll(["--tweakClass", "baritone.launch.BaritoneTweaker"]) + args.addAll(["--tweakClass", "baritone.launch.tweaker.BaritoneTweaker"]) } } @@ -38,14 +38,15 @@ configurations { } dependencies { - implementation "org.spongepowered:mixin:0.8.5" + implementation "org.spongepowered:mixin:${project.mixin_version}" // for some reason mixin isn't including these... - implementation "org.ow2.asm:asm:9.3" - implementation "org.ow2.asm:asm-tree:9.3" - implementation "org.ow2.asm:asm-commons:9.3" - implementation "org.ow2.asm:asm-util:9.3" - implementation "org.ow2.asm:asm-analysis:9.3" + implementation "org.ow2.asm:asm:${project.asm_version}" + implementation "org.ow2.asm:asm-tree:${project.asm_version}" + implementation "org.ow2.asm:asm-commons:${project.asm_version}" + implementation "org.ow2.asm:asm-util:${project.asm_version}" + implementation "org.ow2.asm:asm-analysis:${project.asm_version}" + implementation 'com.github.ImpactDevelopment:SimpleTweaker:1.2' implementation('net.minecraft:launchwrapper:of-2.3') { @@ -66,18 +67,18 @@ dependencies { shadowJar { configurations = [project.configurations.shadowCommon] - classifier "dev-shadow" + archiveClassifier.set "dev-shadow" } remapJar { inputFile.set shadowJar.archiveFile dependsOn shadowJar - classifier null + archiveClassifier.set null } jar { - classifier "dev" + archiveClassifier.set "dev" preserveFileTimestamps = false reproducibleFileOrder = true @@ -94,8 +95,7 @@ jar { } task proguard(type: ProguardTask) { - url 'https://github.com/Guardsquare/proguard/releases/download/v7.2.1/proguard-7.2.1.zip' - extract 'proguard-7.2.1/lib/proguard.jar' + proguardVersion "7.2.1" } task createDist(type: CreateDistTask, dependsOn: proguard) diff --git a/tweaker/src/main/java/baritone/launch/BaritoneTweaker.java b/tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java similarity index 98% rename from tweaker/src/main/java/baritone/launch/BaritoneTweaker.java rename to tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java index b9db9b6a5..694aef533 100644 --- a/tweaker/src/main/java/baritone/launch/BaritoneTweaker.java +++ b/tweaker/src/main/java/baritone/launch/tweaker/BaritoneTweaker.java @@ -15,7 +15,7 @@ * along with Baritone. If not, see . */ -package baritone.launch; +package baritone.launch.tweaker; import io.github.impactdevelopment.simpletweaker.SimpleTweaker; import net.minecraft.launchwrapper.Launch;